]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
net_vampire: restructure internal code more.
authorGünther Deschner <gd@samba.org>
Thu, 12 Jun 2008 10:35:46 +0000 (12:35 +0200)
committerGünther Deschner <gd@samba.org>
Fri, 13 Jun 2008 21:39:08 +0000 (23:39 +0200)
Guenther

source/utils/net.h
source/utils/net_rpc_samsync.c

index e5bd2ab6920cf33c02349dce46063dffe0ec94f8..627ac0aaa1a728996ecb2a29e18018eb29a2af5c 100644 (file)
@@ -158,3 +158,33 @@ typedef struct _accountmap {
        uint32_t rid;
        const char *cn;
 } ACCOUNTMAP;
+
+enum net_samsync_mode {
+       NET_SAMSYNC_MODE_FETCH_PASSDB = 0,
+       NET_SAMSYNC_MODE_FETCH_LDIF = 1,
+       NET_SAMSYNC_MODE_DUMP = 2
+};
+
+struct samsync_ldif_context {
+       GROUPMAP *groupmap;
+       ACCOUNTMAP *accountmap;
+       bool initialized;
+       const char *add_template;
+       const char *mod_template;
+       char *add_name;
+       char *mod_name;
+       FILE *add_file;
+       FILE *mod_file;
+       FILE *ldif_file;
+       const char *suffix;
+       int num_alloced;
+};
+
+struct samsync_context {
+       enum net_samsync_mode mode;
+       const struct dom_sid *domain_sid;
+       const char *domain_sid_str;
+       const char *ldif_filename;
+
+       struct samsync_ldif_context *ldif;
+};
index cdda0232d80683fedd9daf89962f231d92d304c9..f6483bdba2c8c76b6a2fa86377daa89bab00e452 100644 (file)
 /* uid's and gid's for writing deltas to ldif */
 static uint32 ldif_gid = 999;
 static uint32 ldif_uid = 999;
-/* Keep track of ldap initialization */
-static int init_ldap = 1;
-
-enum net_samsync_mode {
-       NET_SAMSYNC_MODE_FETCH_PASSDB = 0,
-       NET_SAMSYNC_MODE_DUMP = 1
-};
 
 static void display_group_mem_info(uint32_t rid,
                                   struct netr_DELTA_GROUP_MEMBER *r)
@@ -177,8 +170,11 @@ static void display_group_info(uint32_t rid, struct netr_DELTA_GROUP *r)
        d_printf("desc='%s', rid=%u\n", r->description.string, rid);
 }
 
-static NTSTATUS display_sam_entry(struct netr_DELTA_ENUM *r,
-                             const DOM_SID *domain_sid)
+static NTSTATUS display_sam_entry(TALLOC_CTX *mem_ctx,
+                                 enum netr_SamDatabaseID database_id,
+                                 struct netr_DELTA_ENUM *r,
+                                 NTSTATUS status,
+                                 struct samsync_context *ctx)
 {
        union netr_DELTA_UNION u = r->delta_union;
        union netr_DELTA_ID_UNION id = r->delta_id_union;
@@ -332,13 +328,33 @@ static NTSTATUS display_sam_entry(struct netr_DELTA_ENUM *r,
        return NT_STATUS_OK;
 }
 
+static NTSTATUS display_sam_entries(TALLOC_CTX *mem_ctx,
+                                   enum netr_SamDatabaseID database_id,
+                                   struct netr_DELTA_ENUM_ARRAY *r,
+                                   NTSTATUS status,
+                                   struct samsync_context *ctx)
+{
+       int i;
+
+       for (i = 0; i < r->num_deltas; i++) {
+               display_sam_entry(mem_ctx, database_id, &r->delta_enum[i], status, ctx);
+       }
+
+       return NT_STATUS_OK;
+}
+
+typedef NTSTATUS (*samsync_fn_t)(TALLOC_CTX *,
+                                enum netr_SamDatabaseID,
+                                struct netr_DELTA_ENUM_ARRAY *,
+                                NTSTATUS,
+                                struct samsync_context *);
+
 static NTSTATUS process_database(struct rpc_pipe_client *pipe_hnd,
                                 enum netr_SamDatabaseID database_id,
-                                enum net_samsync_mode mode,
-                                NTSTATUS (*callback_fn)(struct netr_DELTA_ENUM *, const DOM_SID *), const DOM_SID *domain_sid)
+                                samsync_fn_t callback_fn,
+                                struct samsync_context *ctx)
 {
        NTSTATUS result;
-       int i;
        TALLOC_CTX *mem_ctx;
        const char *logon_server = pipe_hnd->desthost;
        const char *computername = global_myname();
@@ -355,12 +371,15 @@ static NTSTATUS process_database(struct rpc_pipe_client *pipe_hnd,
                return NT_STATUS_NO_MEMORY;
        }
 
-       switch (mode) {
+       switch (ctx->mode) {
                case NET_SAMSYNC_MODE_DUMP:
-                       action = "Dumping";
+                       action = "Dumping (to stdout)";
                        break;
                case NET_SAMSYNC_MODE_FETCH_PASSDB:
-                       action = "Fetching";
+                       action = "Fetching (to passdb)";
+                       break;
+               case NET_SAMSYNC_MODE_FETCH_LDIF:
+                       action = "Fetching (to ldif)";
                        break;
                default:
                        action = "Unknown";
@@ -369,16 +388,16 @@ static NTSTATUS process_database(struct rpc_pipe_client *pipe_hnd,
 
        switch (database_id) {
        case SAM_DATABASE_DOMAIN:
-               d_printf("%s DOMAIN database\n", action);
+               d_fprintf(stderr, "%s DOMAIN database\n", action);
                break;
        case SAM_DATABASE_BUILTIN:
-               d_printf("%s BUILTIN database\n", action);
+               d_fprintf(stderr, "%s BUILTIN database\n", action);
                break;
        case SAM_DATABASE_PRIVS:
-               d_printf("%s PRIVS databases\n", action);
+               d_fprintf(stderr, "%s PRIVS databases\n", action);
                break;
        default:
-               d_printf("%s unknown database type %u\n",
+               d_fprintf(stderr, "%s unknown database type %u\n",
                        action, database_id);
                break;
        }
@@ -398,6 +417,9 @@ static NTSTATUS process_database(struct rpc_pipe_client *pipe_hnd,
                                                   &sync_context,
                                                   &delta_enum_array,
                                                   0xffff);
+               if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
+                       return result;
+               }
 
                /* Check returned credentials. */
                if (!netlogon_creds_client_check(pipe_hnd->dc,
@@ -418,14 +440,14 @@ static NTSTATUS process_database(struct rpc_pipe_client *pipe_hnd,
                                        database_id,
                                        delta_enum_array);
 
-               /* Display results */
-               for (i = 0; i < delta_enum_array->num_deltas; i++) {
-                       callback_fn(&delta_enum_array->delta_enum[i],
-                                   domain_sid);
-                }
+               /* Process results */
+               callback_fn(mem_ctx, database_id, delta_enum_array, result, ctx);
 
                TALLOC_FREE(delta_enum_array);
 
+               /* Increment sync_context */
+               sync_context += 1;
+
        } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
 
        talloc_destroy(mem_ctx);
@@ -443,17 +465,22 @@ NTSTATUS rpc_samdump_internals(struct net_context *c,
                                int argc,
                                const char **argv)
 {
+       struct samsync_context *ctx;
+
+       ctx = TALLOC_ZERO_P(mem_ctx, struct samsync_context);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+       ctx->mode = NET_SAMSYNC_MODE_DUMP;
+       ctx->domain_sid = domain_sid;
+
        process_database(pipe_hnd, SAM_DATABASE_DOMAIN,
-                        NET_SAMSYNC_MODE_DUMP,
-                        display_sam_entry, domain_sid);
+                        display_sam_entries, ctx);
 
        process_database(pipe_hnd, SAM_DATABASE_BUILTIN,
-                        NET_SAMSYNC_MODE_DUMP,
-                        display_sam_entry, domain_sid);
+                        display_sam_entries, ctx);
 
        process_database(pipe_hnd, SAM_DATABASE_PRIVS,
-                        NET_SAMSYNC_MODE_DUMP,
-                        display_sam_entry, domain_sid);
+                        display_sam_entries, ctx);
 
        return NT_STATUS_OK;
 }
@@ -1116,7 +1143,10 @@ static NTSTATUS fetch_domain_info(uint32_t rid,
        return NT_STATUS_OK;
 }
 
-static NTSTATUS fetch_sam_entry(struct netr_DELTA_ENUM *r, const DOM_SID *dom_sid)
+static NTSTATUS fetch_sam_entry(TALLOC_CTX *mem_ctx,
+                               enum netr_SamDatabaseID database_id,
+                               struct netr_DELTA_ENUM *r,
+                               struct samsync_context *ctx)
 {
        switch(r->delta_type) {
        case NETR_DELTA_USER:
@@ -1134,12 +1164,12 @@ static NTSTATUS fetch_sam_entry(struct netr_DELTA_ENUM *r, const DOM_SID *dom_si
        case NETR_DELTA_ALIAS:
                fetch_alias_info(r->delta_id_union.rid,
                                 r->delta_union.alias,
-                                dom_sid);
+                                ctx->domain_sid);
                break;
        case NETR_DELTA_ALIAS_MEMBER:
                fetch_alias_mem(r->delta_id_union.rid,
                                r->delta_union.alias_member,
-                               dom_sid);
+                               ctx->domain_sid);
                break;
        case NETR_DELTA_DOMAIN:
                fetch_domain_info(r->delta_id_union.rid,
@@ -1202,8 +1232,28 @@ static NTSTATUS fetch_sam_entry(struct netr_DELTA_ENUM *r, const DOM_SID *dom_si
        return NT_STATUS_OK;
 }
 
-static NTSTATUS populate_ldap_for_ldif(fstring sid, const char *suffix, const char
-                      *builtin_sid, FILE *add_fd)
+static NTSTATUS fetch_sam_entries(TALLOC_CTX *mem_ctx,
+                                 enum netr_SamDatabaseID database_id,
+                                 struct netr_DELTA_ENUM_ARRAY *r,
+                                 NTSTATUS status,
+                                 struct samsync_context *ctx)
+{
+       int i;
+
+       for (i = 0; i < r->num_deltas; i++) {
+               fetch_sam_entry(mem_ctx, database_id, &r->delta_enum[i], ctx);
+       }
+
+       return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS populate_ldap_for_ldif(const char *sid,
+                                      const char *suffix,
+                                      const char *builtin_sid,
+                                      FILE *add_fd)
 {
        const char *user_suffix, *group_suffix, *machine_suffix, *idmap_suffix;
        char *user_attr=NULL, *group_attr=NULL;
@@ -1459,10 +1509,13 @@ static NTSTATUS populate_ldap_for_ldif(fstring sid, const char *suffix, const ch
        return NT_STATUS_OK;
 }
 
+/****************************************************************
+****************************************************************/
+
 static NTSTATUS map_populate_groups(TALLOC_CTX *mem_ctx,
                                    GROUPMAP *groupmap,
                                    ACCOUNTMAP *accountmap,
-                                   fstring sid,
+                                   const char *sid,
                                    const char *suffix,
                                    const char *builtin_sid)
 {
@@ -1631,20 +1684,20 @@ static int fprintf_attr(FILE *add_fd, const char *attr_name,
        return res;
 }
 
+/****************************************************************
+****************************************************************/
+
 static NTSTATUS fetch_group_info_to_ldif(TALLOC_CTX *mem_ctx,
                                         struct netr_DELTA_GROUP *r,
                                         GROUPMAP *groupmap,
                                         FILE *add_fd,
-                                        fstring sid,
-                                        char *suffix)
+                                        const char *sid,
+                                        const char *suffix)
 {
-       fstring groupname;
+       const char *groupname = r->group_name.string;
        uint32 grouptype = 0, g_rid = 0;
        char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
 
-       /* Get the group name */
-       fstrcpy(groupname, r->group_name.string);
-
        /* Set up the group type (always 2 for group info) */
        grouptype = 2;
 
@@ -1694,12 +1747,16 @@ static NTSTATUS fetch_group_info_to_ldif(TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
+/****************************************************************
+****************************************************************/
+
 static NTSTATUS fetch_account_info_to_ldif(TALLOC_CTX *mem_ctx,
                                           struct netr_DELTA_USER *r,
                                           GROUPMAP *groupmap,
                                           ACCOUNTMAP *accountmap,
                                           FILE *add_fd,
-                                          fstring sid, char *suffix,
+                                          const char *sid,
+                                          const char *suffix,
                                           int alloced)
 {
        fstring username, logonscript, homedrive, homepath = "", homedir = "";
@@ -1841,12 +1898,16 @@ static NTSTATUS fetch_account_info_to_ldif(TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
+/****************************************************************
+****************************************************************/
+
 static NTSTATUS fetch_alias_info_to_ldif(TALLOC_CTX *mem_ctx,
                                         struct netr_DELTA_ALIAS *r,
                                         GROUPMAP *groupmap,
-                                        FILE *add_fd, fstring sid,
-                                        char *suffix,
-                                        unsigned db_type)
+                                        FILE *add_fd,
+                                        const char *sid,
+                                        const char *suffix,
+                                        enum netr_SamDatabaseID database_id)
 {
        fstring aliasname, description;
        uint32 grouptype = 0, g_rid = 0;
@@ -1859,7 +1920,7 @@ static NTSTATUS fetch_alias_info_to_ldif(TALLOC_CTX *mem_ctx,
        fstrcpy(description, r->description.string);
 
        /* Set up the group type */
-       switch (db_type) {
+       switch (database_id) {
        case SAM_DATABASE_DOMAIN:
                grouptype = 4;
                break;
@@ -1919,6 +1980,9 @@ static NTSTATUS fetch_alias_info_to_ldif(TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
+/****************************************************************
+****************************************************************/
+
 static NTSTATUS fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER *r,
                                            uint32_t id_rid,
                                            GROUPMAP *groupmap,
@@ -1964,324 +2028,370 @@ static NTSTATUS fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER *r,
        return NT_STATUS_OK;
 }
 
-static NTSTATUS fetch_database_to_ldif(struct rpc_pipe_client *pipe_hnd,
-                                      uint32 db_type,
-                                      const DOM_SID *dom_sid,
-                                      const char *user_file)
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS ldif_init_context(TALLOC_CTX *mem_ctx,
+                                 struct samsync_context *ctx,
+                                 enum netr_SamDatabaseID database_id)
 {
-       char *suffix;
-       const char *builtin_sid = "S-1-5-32";
-       char *add_name = NULL, *mod_name = NULL;
+       NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+       struct samsync_ldif_context *r;
        const char *add_template = "/tmp/add.ldif.XXXXXX";
        const char *mod_template = "/tmp/mod.ldif.XXXXXX";
-       fstring sid, domainname;
-       NTSTATUS ret = NT_STATUS_OK, result;
-       int k;
-       TALLOC_CTX *mem_ctx;
-       uint32 num_deltas;
-       FILE *add_file = NULL, *mod_file = NULL, *ldif_file = NULL;
-       int num_alloced = 0, g_index = 0, a_index = 0;
-       const char *logon_server = pipe_hnd->desthost;
-       const char *computername = global_myname();
-       struct netr_Authenticator credential;
-       struct netr_Authenticator return_authenticator;
-       enum netr_SamDatabaseID database_id = db_type;
-       uint16_t restart_state = 0;
-       uint32_t sync_context = 0;
-       DATA_BLOB session_key;
+       const char *builtin_sid = "S-1-5-32";
 
-       /* Set up array for mapping accounts to groups */
-       /* Array element is the group rid */
-       GROUPMAP *groupmap = NULL;
+       if (ctx->ldif && ctx->ldif->initialized) {
+               return NT_STATUS_OK;
+       }
 
-       /* Set up array for mapping account rid's to cn's */
-       /* Array element is the account rid */
-       ACCOUNTMAP *accountmap = NULL;
+       r = TALLOC_ZERO_P(mem_ctx, struct samsync_ldif_context);
+       NT_STATUS_HAVE_NO_MEMORY(r);
 
-       if (!(mem_ctx = talloc_init("fetch_database"))) {
-               return NT_STATUS_NO_MEMORY;
+       /* Get other smb.conf data */
+       if (!(lp_workgroup()) || !*(lp_workgroup())) {
+               DEBUG(0,("workgroup missing from smb.conf--exiting\n"));
+               exit(1);
        }
 
+       /* Get the ldap suffix */
+       r->suffix = lp_ldap_suffix();
+       if (r->suffix == NULL || strcmp(r->suffix, "") == 0) {
+               DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
+               exit(1);
+       }
+
+       /* Get the sid */
+       ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
+       NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid_str);
+
        /* Ensure we have an output file */
-       if (user_file)
-               ldif_file = fopen(user_file, "a");
-       else
-               ldif_file = stdout;
+       if (ctx->ldif_filename) {
+               r->ldif_file = fopen(ctx->ldif_filename, "a");
+       } else {
+               r->ldif_file = stdout;
+       }
 
-       if (!ldif_file) {
-               fprintf(stderr, "Could not open %s\n", user_file);
-               DEBUG(1, ("Could not open %s\n", user_file));
-               ret = NT_STATUS_UNSUCCESSFUL;
+       if (!r->ldif_file) {
+               fprintf(stderr, "Could not open %s\n", ctx->ldif_filename);
+               DEBUG(1, ("Could not open %s\n", ctx->ldif_filename));
+               status = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
 
-       add_name = talloc_strdup(mem_ctx, add_template);
-       mod_name = talloc_strdup(mem_ctx, mod_template);
-       if (!add_name || !mod_name) {
-               ret = NT_STATUS_NO_MEMORY;
+       r->add_template = talloc_strdup(mem_ctx, add_template);
+       r->mod_template = talloc_strdup(mem_ctx, mod_template);
+       if (!r->add_template || !r->mod_template) {
+               status = NT_STATUS_NO_MEMORY;
                goto done;
        }
 
-       /* Open the add and mod ldif files */
-       if (!(add_file = fdopen(smb_mkstemp(add_name),"w"))) {
-               DEBUG(1, ("Could not open %s\n", add_name));
-               ret = NT_STATUS_UNSUCCESSFUL;
+       r->add_name = talloc_strdup(mem_ctx, add_template);
+       r->mod_name = talloc_strdup(mem_ctx, mod_template);
+       if (!r->add_name || !r->mod_name) {
+               status = NT_STATUS_NO_MEMORY;
                goto done;
        }
-       if (!(mod_file = fdopen(smb_mkstemp(mod_name),"w"))) {
-               DEBUG(1, ("Could not open %s\n", mod_name));
-               ret = NT_STATUS_UNSUCCESSFUL;
+
+       /* Open the add and mod ldif files */
+       if (!(r->add_file = fdopen(smb_mkstemp(r->add_name),"w"))) {
+               DEBUG(1, ("Could not open %s\n", r->add_name));
+               status = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
-
-       /* Get the sid */
-       sid_to_fstring(sid, dom_sid);
-
-       /* Get the ldap suffix */
-       suffix = lp_ldap_suffix();
-       if (suffix == NULL || strcmp(suffix, "") == 0) {
-               DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
-               exit(1);
+       if (!(r->mod_file = fdopen(smb_mkstemp(r->mod_name),"w"))) {
+               DEBUG(1, ("Could not open %s\n", r->mod_name));
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto done;
        }
 
-       /* Get other smb.conf data */
-       if (!(lp_workgroup()) || !*(lp_workgroup())) {
-               DEBUG(0,("workgroup missing from smb.conf--exiting\n"));
-               exit(1);
+       /* Allocate initial memory for groupmap and accountmap arrays */
+       r->groupmap = TALLOC_ZERO_ARRAY(mem_ctx, GROUPMAP, 8);
+       r->accountmap = TALLOC_ZERO_ARRAY(mem_ctx, ACCOUNTMAP, 8);
+       if (r->groupmap == NULL || r->accountmap == NULL) {
+               DEBUG(1,("GROUPMAP talloc failed\n"));
+               status = NT_STATUS_NO_MEMORY;
+               goto done;
        }
 
-       /* Allocate initial memory for groupmap and accountmap arrays */
-       if (init_ldap == 1) {
-               groupmap = TALLOC_ZERO_ARRAY(mem_ctx, GROUPMAP, 8);
-               accountmap = TALLOC_ZERO_ARRAY(mem_ctx, ACCOUNTMAP, 8);
-               if (groupmap == NULL || accountmap == NULL) {
-                       DEBUG(1,("GROUPMAP malloc failed\n"));
-                       ret = NT_STATUS_NO_MEMORY;
-                       goto done;
-               }
+       /* Remember how many we malloced */
+       r->num_alloced = 8;
 
-               /* Remember how many we malloced */
-               num_alloced = 8;
+       /* Initial database population */
+       if (database_id == SAM_DATABASE_DOMAIN) {
 
-               /* Initial database population */
-               ret = populate_ldap_for_ldif(sid, suffix, builtin_sid, add_file);
-               if (!NT_STATUS_IS_OK(ret)) {
+               status = populate_ldap_for_ldif(ctx->domain_sid_str,
+                                               r->suffix,
+                                               builtin_sid,
+                                               r->add_file);
+               if (!NT_STATUS_IS_OK(status)) {
                        goto done;
                }
-               ret = map_populate_groups(mem_ctx, groupmap, accountmap, sid, suffix,
-                                   builtin_sid);
-               if (!NT_STATUS_IS_OK(ret)) {
+
+               status = map_populate_groups(mem_ctx,
+                                            r->groupmap,
+                                            r->accountmap,
+                                            ctx->domain_sid_str,
+                                            r->suffix,
+                                            builtin_sid);
+               if (!NT_STATUS_IS_OK(status)) {
                        goto done;
                }
-
-               /* Don't do this again */
-               init_ldap = 0;
        }
 
-       /* Announce what we are doing */
-       switch( db_type ) {
-       case SAM_DATABASE_DOMAIN:
-               d_fprintf(stderr, "Fetching DOMAIN database\n");
-               break;
-       case SAM_DATABASE_BUILTIN:
-               d_fprintf(stderr, "Fetching BUILTIN database\n");
-               break;
-       case SAM_DATABASE_PRIVS:
-               d_fprintf(stderr, "Fetching PRIVS databases\n");
-               break;
-       default:
-               d_fprintf(stderr,
-                         "Fetching unknown database type %u\n",
-                         db_type );
-               break;
-       }
+       r->initialized = true;
 
-       do {
-               struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
-
-               netlogon_creds_client_step(pipe_hnd->dc, &credential);
+       ctx->ldif = r;
 
-               result = rpccli_netr_DatabaseSync2(pipe_hnd, mem_ctx,
-                                                  logon_server,
-                                                  computername,
-                                                  &credential,
-                                                  &return_authenticator,
-                                                  database_id,
-                                                  restart_state,
-                                                  &sync_context,
-                                                  &delta_enum_array,
-                                                  0xffff);
-
-               /* Check returned credentials. */
-               if (!netlogon_creds_client_check(pipe_hnd->dc,
-                                                &return_authenticator.cred)) {
-                       DEBUG(0,("credentials chain check failed\n"));
-                       return NT_STATUS_ACCESS_DENIED;
-               }
-
-               if (NT_STATUS_IS_ERR(result)) {
-                       break;
-               }
-
-               session_key = data_blob_const(pipe_hnd->dc->sess_key, 16);
-
-               samsync_fix_delta_array(mem_ctx,
-                                       &session_key,
-                                       true,
-                                       database_id,
-                                       delta_enum_array);
-
-               num_deltas = delta_enum_array->num_deltas;
-
-               /* Re-allocate memory for groupmap and accountmap arrays */
-               groupmap = TALLOC_REALLOC_ARRAY(mem_ctx, groupmap, GROUPMAP,
-                                            num_deltas+num_alloced);
-               accountmap = TALLOC_REALLOC_ARRAY(mem_ctx, accountmap, ACCOUNTMAP,
-                                              num_deltas+num_alloced);
-               if (groupmap == NULL || accountmap == NULL) {
-                       DEBUG(1,("GROUPMAP talloc failed\n"));
-                       ret = NT_STATUS_NO_MEMORY;
-                       goto done;
-               }
-
-               /* Initialize the new records */
-               memset(&groupmap[num_alloced], 0,
-                      sizeof(GROUPMAP)*num_deltas);
-               memset(&accountmap[num_alloced], 0,
-                      sizeof(ACCOUNTMAP)*num_deltas);
-
-               /* Remember how many we alloced this time */
-               num_alloced += num_deltas;
+       return NT_STATUS_OK;
+ done:
+       TALLOC_FREE(r);
+       return status;
+}
 
-               /* Loop through the deltas */
-               for (k=0; k<num_deltas; k++) {
+/****************************************************************
+****************************************************************/
 
-                       union netr_DELTA_UNION u =
-                               delta_enum_array->delta_enum[k].delta_union;
-                       union netr_DELTA_ID_UNION id =
-                               delta_enum_array->delta_enum[k].delta_id_union;
+static void ldif_free_context(struct samsync_ldif_context *r)
+{
+       if (!r) {
+               return;
+       }
 
-                       switch(delta_enum_array->delta_enum[k].delta_type) {
-                       case NETR_DELTA_DOMAIN:
-                               /* Is this case needed? */
-                               fstrcpy(domainname,
-                                       u.domain->domain_name.string);
-                               break;
+       /* Close and delete the ldif files */
+       if (r->add_file) {
+               fclose(r->add_file);
+       }
 
-                       case NETR_DELTA_GROUP:
-                               fetch_group_info_to_ldif(mem_ctx,
-                                       u.group,
-                                       &groupmap[g_index],
-                                       add_file, sid, suffix);
-                               g_index++;
-                               break;
+       if ((r->add_name != NULL) &&
+           strcmp(r->add_name, r->add_template) && (unlink(r->add_name))) {
+               DEBUG(1,("unlink(%s) failed, error was (%s)\n",
+                        r->add_name, strerror(errno)));
+       }
 
-                       case NETR_DELTA_USER:
-                               fetch_account_info_to_ldif(mem_ctx,
-                                       u.user, groupmap,
-                                       &accountmap[a_index], add_file,
-                                       sid, suffix, num_alloced);
-                               a_index++;
-                               break;
+       if (r->mod_file) {
+               fclose(r->mod_file);
+       }
 
-                       case NETR_DELTA_ALIAS:
-                               fetch_alias_info_to_ldif(mem_ctx,
-                                       u.alias, &groupmap[g_index],
-                                       add_file, sid, suffix, db_type);
-                               g_index++;
-                               break;
+       if ((r->mod_name != NULL) &&
+           strcmp(r->mod_name, r->mod_template) && (unlink(r->mod_name))) {
+               DEBUG(1,("unlink(%s) failed, error was (%s)\n",
+                        r->mod_name, strerror(errno)));
+       }
 
-                       case NETR_DELTA_GROUP_MEMBER:
-                               fetch_groupmem_info_to_ldif(
-                                       u.group_member, id.rid,
-                                       groupmap, accountmap,
-                                       mod_file, num_alloced);
-                               break;
+       if (r->ldif_file && (r->ldif_file != stdout)) {
+               fclose(r->ldif_file);
+       }
 
-                       case NETR_DELTA_ALIAS_MEMBER:
-                       case NETR_DELTA_POLICY:
-                       case NETR_DELTA_ACCOUNT:
-                       case NETR_DELTA_TRUSTED_DOMAIN:
-                       case NETR_DELTA_SECRET:
-                       case NETR_DELTA_RENAME_GROUP:
-                       case NETR_DELTA_RENAME_USER:
-                       case NETR_DELTA_RENAME_ALIAS:
-                       case NETR_DELTA_DELETE_GROUP:
-                       case NETR_DELTA_DELETE_USER:
-                       case NETR_DELTA_MODIFY_COUNT:
-                       default:
-                               break;
-                       } /* end of switch */
-               } /* end of for loop */
+       TALLOC_FREE(r);
+}
 
-               /* Increment sync_context */
-               sync_context += 1;
+/****************************************************************
+****************************************************************/
 
-       } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
+static void ldif_write_output(enum netr_SamDatabaseID database_id,
+                             struct samsync_context *ctx)
+{
+       struct samsync_ldif_context *l = ctx->ldif;
 
        /* Write ldif data to the user's file */
-       if (db_type == SAM_DATABASE_DOMAIN) {
-               fprintf(ldif_file,
+       if (database_id == SAM_DATABASE_DOMAIN) {
+               fprintf(l->ldif_file,
                        "# SAM_DATABASE_DOMAIN: ADD ENTITIES\n");
-               fprintf(ldif_file,
+               fprintf(l->ldif_file,
                        "# =================================\n\n");
-               fflush(ldif_file);
-       } else if (db_type == SAM_DATABASE_BUILTIN) {
-               fprintf(ldif_file,
+               fflush(l->ldif_file);
+       } else if (database_id == SAM_DATABASE_BUILTIN) {
+               fprintf(l->ldif_file,
                        "# SAM_DATABASE_BUILTIN: ADD ENTITIES\n");
-               fprintf(ldif_file,
+               fprintf(l->ldif_file,
                        "# ==================================\n\n");
-               fflush(ldif_file);
+               fflush(l->ldif_file);
        }
-       fseek(add_file, 0, SEEK_SET);
-       transfer_file(fileno(add_file), fileno(ldif_file), (size_t) -1);
+       fseek(l->add_file, 0, SEEK_SET);
+       transfer_file(fileno(l->add_file), fileno(l->ldif_file), (size_t) -1);
 
-       if (db_type == SAM_DATABASE_DOMAIN) {
-               fprintf(ldif_file,
+       if (database_id == SAM_DATABASE_DOMAIN) {
+               fprintf(l->ldif_file,
                        "# SAM_DATABASE_DOMAIN: MODIFY ENTITIES\n");
-               fprintf(ldif_file,
+               fprintf(l->ldif_file,
                        "# ====================================\n\n");
-               fflush(ldif_file);
-       } else if (db_type == SAM_DATABASE_BUILTIN) {
-               fprintf(ldif_file,
+               fflush(l->ldif_file);
+       } else if (database_id == SAM_DATABASE_BUILTIN) {
+               fprintf(l->ldif_file,
                        "# SAM_DATABASE_BUILTIN: MODIFY ENTITIES\n");
-               fprintf(ldif_file,
+               fprintf(l->ldif_file,
                        "# =====================================\n\n");
-               fflush(ldif_file);
+               fflush(l->ldif_file);
        }
-       fseek(mod_file, 0, SEEK_SET);
-       transfer_file(fileno(mod_file), fileno(ldif_file), (size_t) -1);
+       fseek(l->mod_file, 0, SEEK_SET);
+       transfer_file(fileno(l->mod_file), fileno(l->ldif_file), (size_t) -1);
+}
 
+/****************************************************************
+****************************************************************/
 
- done:
-       /* Close and delete the ldif files */
-       if (add_file) {
-               fclose(add_file);
+static NTSTATUS fetch_sam_entry_ldif(TALLOC_CTX *mem_ctx,
+                                    enum netr_SamDatabaseID database_id,
+                                    struct netr_DELTA_ENUM *r,
+                                    struct samsync_context *ctx,
+                                    uint32_t *a_index,
+                                    uint32_t *g_index)
+{
+       union netr_DELTA_UNION u = r->delta_union;
+       union netr_DELTA_ID_UNION id = r->delta_id_union;
+       struct samsync_ldif_context *l = ctx->ldif;
+
+       switch (r->delta_type) {
+               case NETR_DELTA_DOMAIN:
+                       break;
+
+               case NETR_DELTA_GROUP:
+                       fetch_group_info_to_ldif(mem_ctx,
+                                                u.group,
+                                                &l->groupmap[*g_index],
+                                                l->add_file,
+                                                ctx->domain_sid_str,
+                                                l->suffix);
+                       (*g_index)++;
+                       break;
+
+               case NETR_DELTA_USER:
+                       fetch_account_info_to_ldif(mem_ctx,
+                                                  u.user,
+                                                  l->groupmap,
+                                                  &l->accountmap[*a_index],
+                                                  l->add_file,
+                                                  ctx->domain_sid_str,
+                                                  l->suffix,
+                                                  l->num_alloced);
+                       (*a_index)++;
+                       break;
+
+               case NETR_DELTA_ALIAS:
+                       fetch_alias_info_to_ldif(mem_ctx,
+                                                u.alias,
+                                                &l->groupmap[*g_index],
+                                                l->add_file,
+                                                ctx->domain_sid_str,
+                                                l->suffix,
+                                                database_id);
+                       (*g_index)++;
+                       break;
+
+               case NETR_DELTA_GROUP_MEMBER:
+                       fetch_groupmem_info_to_ldif(u.group_member,
+                                                   id.rid,
+                                                   l->groupmap,
+                                                   l->accountmap,
+                                                   l->mod_file,
+                                                   l->num_alloced);
+                       break;
+
+               case NETR_DELTA_ALIAS_MEMBER:
+               case NETR_DELTA_POLICY:
+               case NETR_DELTA_ACCOUNT:
+               case NETR_DELTA_TRUSTED_DOMAIN:
+               case NETR_DELTA_SECRET:
+               case NETR_DELTA_RENAME_GROUP:
+               case NETR_DELTA_RENAME_USER:
+               case NETR_DELTA_RENAME_ALIAS:
+               case NETR_DELTA_DELETE_GROUP:
+               case NETR_DELTA_DELETE_USER:
+               case NETR_DELTA_MODIFY_COUNT:
+               default:
+                       break;
+       } /* end of switch */
+
+       return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS ldif_realloc_maps(TALLOC_CTX *mem_ctx,
+                                 struct samsync_context *ctx,
+                                 uint32_t num_entries)
+{
+       struct samsync_ldif_context *l = ctx->ldif;
+
+       if (!l) {
+               return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if ((add_name != NULL) &&
-           strcmp(add_name, add_template) && (unlink(add_name))) {
-               DEBUG(1,("unlink(%s) failed, error was (%s)\n",
-                        add_name, strerror(errno)));
+       /* Re-allocate memory for groupmap and accountmap arrays */
+       l->groupmap = TALLOC_REALLOC_ARRAY(mem_ctx,
+                                          l->groupmap,
+                                          GROUPMAP,
+                                          num_entries + l->num_alloced);
+
+       l->accountmap = TALLOC_REALLOC_ARRAY(mem_ctx,
+                                            l->accountmap,
+                                            ACCOUNTMAP,
+                                            num_entries + l->num_alloced);
+
+       if (l->groupmap == NULL || l->accountmap == NULL) {
+               DEBUG(1,("GROUPMAP talloc failed\n"));
+               return NT_STATUS_NO_MEMORY;
        }
 
-       if (mod_file) {
-               fclose(mod_file);
+       /* Initialize the new records */
+       memset(&(l->groupmap[l->num_alloced]), 0,
+              sizeof(GROUPMAP) * num_entries);
+       memset(&(l->accountmap[l->num_alloced]), 0,
+              sizeof(ACCOUNTMAP) * num_entries);
+
+       /* Remember how many we alloced this time */
+       l->num_alloced += num_entries;
+
+       return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
+                                      enum netr_SamDatabaseID database_id,
+                                      struct netr_DELTA_ENUM_ARRAY *r,
+                                      NTSTATUS result,
+                                      struct samsync_context *ctx)
+{
+       NTSTATUS status;
+       int i;
+       uint32_t g_index = 0, a_index = 0;
+
+       status = ldif_init_context(mem_ctx, ctx, database_id);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto failed;
        }
 
-       if ((mod_name != NULL) &&
-           strcmp(mod_name, mod_template) && (unlink(mod_name))) {
-               DEBUG(1,("unlink(%s) failed, error was (%s)\n",
-                        mod_name, strerror(errno)));
+       status = ldif_realloc_maps(mem_ctx, ctx, r->num_deltas);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto failed;
        }
 
-       if (ldif_file && (ldif_file != stdout)) {
-               fclose(ldif_file);
+       for (i = 0; i < r->num_deltas; i++) {
+               status = fetch_sam_entry_ldif(mem_ctx, database_id,
+                                             &r->delta_enum[i], ctx,
+                                             &g_index, &a_index);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto failed;
+               }
        }
 
-       /* Return */
-       talloc_destroy(mem_ctx);
-       return ret;
+       /* This was the last query */
+       if (NT_STATUS_IS_OK(result)) {
+               ldif_write_output(database_id, ctx);
+               ldif_free_context(ctx->ldif);
+               ctx->ldif = NULL;
+       }
+
+       return NT_STATUS_OK;
+
+ failed:
+       ldif_free_context(ctx->ldif);
+
+       return status;
 }
 
 /**
@@ -2319,6 +2429,11 @@ NTSTATUS rpc_vampire_internals(struct net_context *c,
         NTSTATUS result;
        fstring my_dom_sid_str;
        fstring rem_dom_sid_str;
+       struct samsync_context *ctx;
+       samsync_fn_t *fn;
+
+       ctx = TALLOC_ZERO_P(mem_ctx, struct samsync_context);
+       NT_STATUS_HAVE_NO_MEMORY(ctx);
 
        if (!sid_equal(domain_sid, get_global_sam_sid())) {
                d_printf("Cannot import users from %s at this time, "
@@ -2337,14 +2452,18 @@ NTSTATUS rpc_vampire_internals(struct net_context *c,
        }
 
         if (argc >= 1 && (strcmp(argv[0], "ldif") == 0)) {
-               result = fetch_database_to_ldif(pipe_hnd, SAM_DATABASE_DOMAIN,
-                                               domain_sid, argv[1]);
-        } else {
-               result = process_database(pipe_hnd, SAM_DATABASE_DOMAIN,
-                                         NET_SAMSYNC_MODE_FETCH_PASSDB,
-                                         fetch_sam_entry, domain_sid);
-        }
+               ctx->mode = NET_SAMSYNC_MODE_FETCH_LDIF;
+               ctx->ldif_filename = argv[1];
+               fn = (samsync_fn_t *)fetch_sam_entries_ldif;
+       } else {
+               ctx->mode = NET_SAMSYNC_MODE_FETCH_PASSDB;
+               fn = (samsync_fn_t *)fetch_sam_entries;
+       }
 
+       /* fetch domain */
+       ctx->domain_sid = domain_sid;
+       result = process_database(pipe_hnd, SAM_DATABASE_DOMAIN,
+                                 (samsync_fn_t)fn, ctx);
        if (!NT_STATUS_IS_OK(result)) {
                d_fprintf(stderr, "Failed to fetch domain database: %s\n",
                          nt_errstr(result));
@@ -2354,15 +2473,10 @@ NTSTATUS rpc_vampire_internals(struct net_context *c,
                goto fail;
        }
 
-        if (argc >= 1 && (strcmp(argv[0], "ldif") == 0)) {
-               result = fetch_database_to_ldif(pipe_hnd, SAM_DATABASE_BUILTIN,
-                                               &global_sid_Builtin, argv[1]);
-        } else {
-               result = process_database(pipe_hnd, SAM_DATABASE_BUILTIN,
-                                         NET_SAMSYNC_MODE_FETCH_PASSDB,
-                                         fetch_sam_entry, &global_sid_Builtin);
-        }
-
+       /* fetch builtin */
+       ctx->domain_sid = &global_sid_Builtin;
+       result = process_database(pipe_hnd, SAM_DATABASE_BUILTIN,
+                                 (samsync_fn_t)fn, ctx);
        if (!NT_STATUS_IS_OK(result)) {
                d_fprintf(stderr, "Failed to fetch builtin database: %s\n",
                          nt_errstr(result));