s3:libnet: accept empty realm for AD domains when only security=domain is set.
[samba.git] / source3 / libnet / libnet_samsync_ldif.c
index 245ebe0b9f9407bb8c8555c4d6bd971f17c8edcb..198373e23d256ed7048945fe1214b5d3a78aefb4 100644 (file)
 */
 
 #include "includes.h"
+#include "system/filesys.h"
 #include "libnet/libnet_samsync.h"
+#include "transfer_file.h"
+#include "passdb.h"
+#include "passdb/pdb_ldap_schema.h"
+#include "lib/util/base64.h"
 
 #ifdef HAVE_LDAP
 
 /* uid's and gid's for writing deltas to ldif */
-static uint32 ldif_gid = 999;
-static uint32 ldif_uid = 999;
+static uint32_t ldif_gid = 999;
+static uint32_t ldif_uid = 999;
+
+/* global counters */
+static uint32_t g_index = 0;
+static uint32_t a_index = 0;
 
 /* Structure for mapping accounts to groups */
 /* Array element is the group rid */
@@ -53,7 +62,7 @@ struct samsync_ldif_context {
        const char *add_template;
        const char *mod_template;
        char *add_name;
-       char *mod_name;
+       char *module_name;
        FILE *add_file;
        FILE *mod_file;
        FILE *ldif_file;
@@ -61,6 +70,33 @@ struct samsync_ldif_context {
        int num_alloced;
 };
 
+/*
+   Returns the substring from src between the first occurrence of
+   the char "front" and the first occurence of the char "back".
+   Mallocs the return string which must be freed.  Not for use
+   with wide character strings.
+*/
+static char *sstring_sub(const char *src, char front, char back)
+{
+       char *temp1, *temp2, *temp3;
+       ptrdiff_t len;
+
+       temp1 = strchr(src, front);
+       if (temp1 == NULL) return NULL;
+       temp2 = strchr(src, back);
+       if (temp2 == NULL) return NULL;
+       len = temp2 - temp1;
+       if (len <= 0) return NULL;
+       temp3 = (char*)SMB_MALLOC(len);
+       if (temp3 == NULL) {
+               DEBUG(1,("Malloc failure in sstring_sub\n"));
+               return NULL;
+       }
+       memcpy(temp3, temp1+1, len-1);
+       temp3[len-1] = '\0';
+       return temp3;
+}
+
 /****************************************************************
 ****************************************************************/
 
@@ -79,6 +115,9 @@ static NTSTATUS populate_ldap_for_ldif(const char *sid,
        if (suffix_attr == NULL) {
                len = strlen(suffix);
                suffix_attr = (char*)SMB_MALLOC(len+1);
+               if (!suffix_attr) {
+                       return NT_STATUS_NO_MEMORY;
+               }
                memcpy(suffix_attr, suffix, len);
                suffix_attr[len] = '\0';
        }
@@ -93,7 +132,7 @@ static NTSTATUS populate_ldap_for_ldif(const char *sid,
        fprintf(add_fd, "\n");
        fflush(add_fd);
 
-       user_suffix = lp_ldap_user_suffix();
+       user_suffix = lp_ldap_user_suffix(talloc_tos());
        if (user_suffix == NULL) {
                SAFE_FREE(suffix_attr);
                return NT_STATUS_NO_MEMORY;
@@ -101,7 +140,7 @@ static NTSTATUS populate_ldap_for_ldif(const char *sid,
        /* If it exists and is distinct from other containers,
           Write the Users entity */
        if (*user_suffix && strcmp(user_suffix, suffix)) {
-               user_attr = sstring_sub(lp_ldap_user_suffix(), '=', ',');
+               user_attr = sstring_sub(lp_ldap_user_suffix(talloc_tos()), '=', ',');
                fprintf(add_fd, "# %s\n", user_suffix);
                fprintf(add_fd, "dn: %s\n", user_suffix);
                fprintf(add_fd, "objectClass: organizationalUnit\n");
@@ -111,7 +150,7 @@ static NTSTATUS populate_ldap_for_ldif(const char *sid,
        }
 
 
-       group_suffix = lp_ldap_group_suffix();
+       group_suffix = lp_ldap_group_suffix(talloc_tos());
        if (group_suffix == NULL) {
                SAFE_FREE(suffix_attr);
                SAFE_FREE(user_attr);
@@ -120,7 +159,7 @@ static NTSTATUS populate_ldap_for_ldif(const char *sid,
        /* If it exists and is distinct from other containers,
           Write the Groups entity */
        if (*group_suffix && strcmp(group_suffix, suffix)) {
-               group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
+               group_attr = sstring_sub(lp_ldap_group_suffix(talloc_tos()), '=', ',');
                fprintf(add_fd, "# %s\n", group_suffix);
                fprintf(add_fd, "dn: %s\n", group_suffix);
                fprintf(add_fd, "objectClass: organizationalUnit\n");
@@ -131,7 +170,7 @@ static NTSTATUS populate_ldap_for_ldif(const char *sid,
 
        /* If it exists and is distinct from other containers,
           Write the Computers entity */
-       machine_suffix = lp_ldap_machine_suffix();
+       machine_suffix = lp_ldap_machine_suffix(talloc_tos());
        if (machine_suffix == NULL) {
                SAFE_FREE(suffix_attr);
                SAFE_FREE(user_attr);
@@ -146,7 +185,7 @@ static NTSTATUS populate_ldap_for_ldif(const char *sid,
                fprintf(add_fd, "objectClass: organizationalUnit\n");
                /* this isn't totally correct as it assumes that
                   there _must_ be an ou. just fixing memleak now. jmcd */
-               machine_ou = sstring_sub(lp_ldap_machine_suffix(), '=', ',');
+               machine_ou = sstring_sub(lp_ldap_machine_suffix(talloc_tos()), '=', ',');
                fprintf(add_fd, "ou: %s\n", machine_ou);
                SAFE_FREE(machine_ou);
                fprintf(add_fd, "\n");
@@ -155,7 +194,7 @@ static NTSTATUS populate_ldap_for_ldif(const char *sid,
 
        /* If it exists and is distinct from other containers,
           Write the IdMap entity */
-       idmap_suffix = lp_ldap_idmap_suffix();
+       idmap_suffix = lp_ldap_idmap_suffix(talloc_tos());
        if (idmap_suffix == NULL) {
                SAFE_FREE(suffix_attr);
                SAFE_FREE(user_attr);
@@ -169,7 +208,7 @@ static NTSTATUS populate_ldap_for_ldif(const char *sid,
                fprintf(add_fd, "# %s\n", idmap_suffix);
                fprintf(add_fd, "dn: %s\n", idmap_suffix);
                fprintf(add_fd, "ObjectClass: organizationalUnit\n");
-               s = sstring_sub(lp_ldap_idmap_suffix(), '=', ',');
+               s = sstring_sub(lp_ldap_idmap_suffix(talloc_tos()), '=', ',');
                fprintf(add_fd, "ou: %s\n", s);
                SAFE_FREE(s);
                fprintf(add_fd, "\n");
@@ -333,7 +372,7 @@ static NTSTATUS map_populate_groups(TALLOC_CTX *mem_ctx,
                                    const char *suffix,
                                    const char *builtin_sid)
 {
-       char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
+       char *group_attr = sstring_sub(lp_ldap_group_suffix(talloc_tos()), '=', ',');
 
        /* Map the groups created by populate_ldap_for_ldif */
        groupmap[0].rid         = 512;
@@ -341,100 +380,129 @@ static NTSTATUS map_populate_groups(TALLOC_CTX *mem_ctx,
        groupmap[0].sambaSID    = talloc_asprintf(mem_ctx, "%s-512", sid);
        groupmap[0].group_dn    = talloc_asprintf(mem_ctx,
                "cn=Domain Admins,ou=%s,%s", group_attr, suffix);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[0].sambaSID);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[0].group_dn);
+       if (groupmap[0].sambaSID == NULL || groupmap[0].group_dn == NULL) {
+               goto err;
+       }
 
        accountmap[0].rid       = 512;
        accountmap[0].cn        = talloc_strdup(mem_ctx, "Domain Admins");
-       NT_STATUS_HAVE_NO_MEMORY(accountmap[0].cn);
+       if (accountmap[0].cn == NULL) {
+               goto err;
+       }
 
        groupmap[1].rid         = 513;
        groupmap[1].gidNumber   = 513;
        groupmap[1].sambaSID    = talloc_asprintf(mem_ctx, "%s-513", sid);
        groupmap[1].group_dn    = talloc_asprintf(mem_ctx,
                "cn=Domain Users,ou=%s,%s", group_attr, suffix);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[1].sambaSID);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[1].group_dn);
+       if (groupmap[1].sambaSID == NULL || groupmap[1].group_dn == NULL) {
+               goto err;
+       }
 
        accountmap[1].rid       = 513;
        accountmap[1].cn        = talloc_strdup(mem_ctx, "Domain Users");
-       NT_STATUS_HAVE_NO_MEMORY(accountmap[1].cn);
+       if (accountmap[1].cn == NULL) {
+               goto err;
+       }
 
        groupmap[2].rid         = 514;
        groupmap[2].gidNumber   = 514;
        groupmap[2].sambaSID    = talloc_asprintf(mem_ctx, "%s-514", sid);
        groupmap[2].group_dn    = talloc_asprintf(mem_ctx,
                "cn=Domain Guests,ou=%s,%s", group_attr, suffix);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[2].sambaSID);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[2].group_dn);
+       if (groupmap[2].sambaSID == NULL || groupmap[2].group_dn == NULL) {
+               goto err;
+       }
 
        accountmap[2].rid       = 514;
        accountmap[2].cn        = talloc_strdup(mem_ctx, "Domain Guests");
-       NT_STATUS_HAVE_NO_MEMORY(accountmap[2].cn);
+       if (accountmap[2].cn == NULL) {
+               goto err;
+       }
 
        groupmap[3].rid         = 515;
        groupmap[3].gidNumber   = 515;
        groupmap[3].sambaSID    = talloc_asprintf(mem_ctx, "%s-515", sid);
        groupmap[3].group_dn    = talloc_asprintf(mem_ctx,
                "cn=Domain Computers,ou=%s,%s", group_attr, suffix);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[3].sambaSID);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[3].group_dn);
+       if (groupmap[3].sambaSID == NULL || groupmap[3].group_dn == NULL) {
+               goto err;
+       }
 
        accountmap[3].rid       = 515;
        accountmap[3].cn        = talloc_strdup(mem_ctx, "Domain Computers");
-       NT_STATUS_HAVE_NO_MEMORY(accountmap[3].cn);
+       if (accountmap[3].cn == NULL) {
+               goto err;
+       }
 
        groupmap[4].rid         = 544;
        groupmap[4].gidNumber   = 544;
        groupmap[4].sambaSID    = talloc_asprintf(mem_ctx, "%s-544", builtin_sid);
        groupmap[4].group_dn    = talloc_asprintf(mem_ctx,
                "cn=Administrators,ou=%s,%s", group_attr, suffix);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[4].sambaSID);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[4].group_dn);
+       if (groupmap[4].sambaSID == NULL || groupmap[4].group_dn == NULL) {
+               goto err;
+       }
 
        accountmap[4].rid       = 515;
        accountmap[4].cn        = talloc_strdup(mem_ctx, "Administrators");
-       NT_STATUS_HAVE_NO_MEMORY(accountmap[4].cn);
+       if (accountmap[4].cn == NULL) {
+               goto err;
+       }
 
        groupmap[5].rid         = 550;
        groupmap[5].gidNumber   = 550;
        groupmap[5].sambaSID    = talloc_asprintf(mem_ctx, "%s-550", builtin_sid);
        groupmap[5].group_dn    = talloc_asprintf(mem_ctx,
                "cn=Print Operators,ou=%s,%s", group_attr, suffix);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[5].sambaSID);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[5].group_dn);
+       if (groupmap[5].sambaSID == NULL || groupmap[5].group_dn == NULL) {
+               goto err;
+       }
 
        accountmap[5].rid       = 550;
        accountmap[5].cn        = talloc_strdup(mem_ctx, "Print Operators");
-       NT_STATUS_HAVE_NO_MEMORY(accountmap[5].cn);
+       if (accountmap[5].cn == NULL) {
+               goto err;
+       }
 
        groupmap[6].rid         = 551;
        groupmap[6].gidNumber   = 551;
        groupmap[6].sambaSID    = talloc_asprintf(mem_ctx, "%s-551", builtin_sid);
        groupmap[6].group_dn    = talloc_asprintf(mem_ctx,
                "cn=Backup Operators,ou=%s,%s", group_attr, suffix);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[6].sambaSID);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[6].group_dn);
+       if (groupmap[6].sambaSID == NULL || groupmap[6].group_dn == NULL) {
+               goto err;
+       }
 
        accountmap[6].rid       = 551;
        accountmap[6].cn        = talloc_strdup(mem_ctx, "Backup Operators");
-       NT_STATUS_HAVE_NO_MEMORY(accountmap[6].cn);
+       if (accountmap[6].cn == NULL) {
+               goto err;
+       }
 
        groupmap[7].rid         = 552;
        groupmap[7].gidNumber   = 552;
        groupmap[7].sambaSID    = talloc_asprintf(mem_ctx, "%s-552", builtin_sid);
        groupmap[7].group_dn    = talloc_asprintf(mem_ctx,
                "cn=Replicators,ou=%s,%s", group_attr, suffix);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[7].sambaSID);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap[7].group_dn);
+       if (groupmap[7].sambaSID == NULL || groupmap[7].group_dn == NULL) {
+               goto err;
+       }
 
        accountmap[7].rid       = 551;
        accountmap[7].cn        = talloc_strdup(mem_ctx, "Replicators");
-       NT_STATUS_HAVE_NO_MEMORY(accountmap[7].cn);
+       if (accountmap[7].cn == NULL) {
+               goto err;
+       }
 
        SAFE_FREE(group_attr);
 
        return NT_STATUS_OK;
+
+  err:
+
+       SAFE_FREE(group_attr);
+       return NT_STATUS_NO_MEMORY;
 }
 
 /*
@@ -509,8 +577,8 @@ static NTSTATUS fetch_group_info_to_ldif(TALLOC_CTX *mem_ctx,
                                         const char *suffix)
 {
        const char *groupname = r->group_name.string;
-       uint32 grouptype = 0, g_rid = 0;
-       char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
+       uint32_t grouptype = 0, g_rid = 0;
+       char *group_attr = sstring_sub(lp_ldap_group_suffix(talloc_tos()), '=', ',');
 
        /* Set up the group type (always 2 for group info) */
        grouptype = 2;
@@ -538,8 +606,10 @@ static NTSTATUS fetch_group_info_to_ldif(TALLOC_CTX *mem_ctx,
        groupmap->sambaSID      = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
        groupmap->group_dn      = talloc_asprintf(mem_ctx,
             "cn=%s,ou=%s,%s", groupname, group_attr, suffix);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap->sambaSID);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap->group_dn);
+       if (groupmap->sambaSID == NULL || groupmap->group_dn == NULL) {
+               SAFE_FREE(group_attr);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        /* Write the data to the temporary add ldif file */
        fprintf(add_fd, "# %s, %s, %s\n", groupname, group_attr,
@@ -580,9 +650,9 @@ static NTSTATUS fetch_account_info_to_ldif(TALLOC_CTX *mem_ctx,
        const char *ou;
        const char* nopasswd = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
        uchar zero_buf[16];
-       uint32 rid = 0, group_rid = 0, gidNumber = 0;
+       uint32_t rid = 0, group_rid = 0, gidNumber = 0;
        time_t unix_time;
-       int i;
+       int i, ret;
 
        memset(zero_buf, '\0', sizeof(zero_buf));
 
@@ -605,9 +675,9 @@ static NTSTATUS fetch_account_info_to_ldif(TALLOC_CTX *mem_ctx,
                } else {
                        snprintf(homedir, sizeof(homedir), "/nobodyshomedir");
                }
-               ou = lp_ldap_user_suffix();
+               ou = lp_ldap_user_suffix(talloc_tos());
        } else {
-               ou = lp_ldap_machine_suffix();
+               ou = lp_ldap_machine_suffix(talloc_tos());
                snprintf(homedir, sizeof(homedir), "/machinehomedir");
        }
 
@@ -656,7 +726,10 @@ static NTSTATUS fetch_account_info_to_ldif(TALLOC_CTX *mem_ctx,
                return NT_STATUS_UNSUCCESSFUL;
        }
        gidNumber = groupmap[i].gidNumber;
-       snprintf(sambaSID, sizeof(sambaSID), groupmap[i].sambaSID);
+       ret = snprintf(sambaSID, sizeof(sambaSID), "%s", groupmap[i].sambaSID);
+       if (ret < 0 || ret == sizeof(sambaSID)) {
+               return NT_STATUS_UNSUCCESSFUL;
+       }
 
        /* Set up sambaAcctFlags */
        flags = pdb_encode_acct_ctrl(r->acct_flags,
@@ -723,8 +796,8 @@ static NTSTATUS fetch_alias_info_to_ldif(TALLOC_CTX *mem_ctx,
                                         enum netr_SamDatabaseID database_id)
 {
        fstring aliasname, description;
-       uint32 grouptype = 0, g_rid = 0;
-       char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
+       uint32_t grouptype = 0, g_rid = 0;
+       char *group_attr = sstring_sub(lp_ldap_group_suffix(talloc_tos()), '=', ',');
 
        /* Get the alias name */
        fstrcpy(aliasname, r->alias_name.string);
@@ -769,7 +842,10 @@ static NTSTATUS fetch_alias_info_to_ldif(TALLOC_CTX *mem_ctx,
        g_rid = r->rid;
        groupmap->gidNumber = ldif_gid;
        groupmap->sambaSID = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
-       NT_STATUS_HAVE_NO_MEMORY(groupmap->sambaSID);
+       if (groupmap->sambaSID == NULL) {
+               SAFE_FREE(group_attr);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        /* Write the data to the temporary add ldif file */
        fprintf(add_fd, "# %s, %s, %s\n", aliasname, group_attr,
@@ -803,7 +879,7 @@ static NTSTATUS fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER *r,
                                            FILE *mod_fd, int alloced)
 {
        fstring group_dn;
-       uint32 group_rid = 0, rid = 0;
+       uint32_t group_rid = 0, rid = 0;
        int i, j, k;
 
        /* Get the dn for the group */
@@ -855,6 +931,14 @@ static NTSTATUS ldif_init_context(TALLOC_CTX *mem_ctx,
        const char *add_template = "/tmp/add.ldif.XXXXXX";
        const char *mod_template = "/tmp/mod.ldif.XXXXXX";
        const char *builtin_sid = "S-1-5-32";
+       mode_t mask;
+       int fd;
+
+       r = talloc_zero(mem_ctx, struct samsync_ldif_context);
+       NT_STATUS_HAVE_NO_MEMORY(r);
+
+       /* Get the ldap suffix */
+       r->suffix = lp_ldap_suffix(talloc_tos());
 
        /* Get other smb.conf data */
        if (!(lp_workgroup()) || !*(lp_workgroup())) {
@@ -863,7 +947,7 @@ static NTSTATUS ldif_init_context(TALLOC_CTX *mem_ctx,
        }
 
        /* Get the ldap suffix */
-       if (!(lp_ldap_suffix()) || !*(lp_ldap_suffix())) {
+       if (!r->suffix || !*r->suffix) {
                DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
                exit(1);
        }
@@ -872,12 +956,6 @@ static NTSTATUS ldif_init_context(TALLOC_CTX *mem_ctx,
                return NT_STATUS_OK;
        }
 
-       r = TALLOC_ZERO_P(mem_ctx, struct samsync_ldif_context);
-       NT_STATUS_HAVE_NO_MEMORY(r);
-
-       /* Get the ldap suffix */
-       r->suffix = lp_ldap_suffix();
-
        /* Ensure we have an output file */
        if (ldif_filename) {
                r->ldif_file = fopen(ldif_filename, "a");
@@ -900,27 +978,50 @@ static NTSTATUS ldif_init_context(TALLOC_CTX *mem_ctx,
        }
 
        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) {
+       r->module_name = talloc_strdup(mem_ctx, mod_template);
+       if (!r->add_name || !r->module_name) {
                status = NT_STATUS_NO_MEMORY;
                goto done;
        }
 
+       mask = umask(S_IRWXO | S_IRWXG);
+       fd = mkstemp(r->add_name);
+       umask(mask);
+       if (fd < 0) {
+               DEBUG(1, ("Could not create %s\n", r->add_name));
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto done;
+       }
+
        /* Open the add and mod ldif files */
-       if (!(r->add_file = fdopen(smb_mkstemp(r->add_name),"w"))) {
+       r->add_file = fdopen(fd, "w");
+       if (r->add_file == NULL) {
                DEBUG(1, ("Could not open %s\n", r->add_name));
+               close(fd);
                status = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
-       if (!(r->mod_file = fdopen(smb_mkstemp(r->mod_name),"w"))) {
-               DEBUG(1, ("Could not open %s\n", r->mod_name));
+
+       mask = umask(S_IRWXO | S_IRWXG);
+       fd = mkstemp(r->module_name);
+       umask(mask);
+       if (fd < 0) {
+               DEBUG(1, ("Could not create %s\n", r->module_name));
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto done;
+       }
+
+       r->mod_file = fdopen(fd, "w");
+       if (r->mod_file == NULL) {
+               DEBUG(1, ("Could not open %s\n", r->module_name));
+               close(fd);
                status = NT_STATUS_UNSUCCESSFUL;
                goto done;
        }
 
        /* 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);
+       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;
@@ -986,10 +1087,10 @@ static void ldif_free_context(struct samsync_ldif_context *r)
                fclose(r->mod_file);
        }
 
-       if ((r->mod_name != NULL) &&
-           strcmp(r->mod_name, r->mod_template) && (unlink(r->mod_name))) {
+       if ((r->module_name != NULL) &&
+           strcmp(r->module_name, r->mod_template) && (unlink(r->module_name))) {
                DEBUG(1,("unlink(%s) failed, error was (%s)\n",
-                        r->mod_name, strerror(errno)));
+                        r->module_name, strerror(errno)));
        }
 
        if (r->ldif_file && (r->ldif_file != stdout)) {
@@ -1046,8 +1147,8 @@ 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)
+                                    uint32_t *a_index_p,
+                                    uint32_t *g_index_p)
 {
        union netr_DELTA_UNION u = r->delta_union;
        union netr_DELTA_ID_UNION id = r->delta_id_union;
@@ -1061,34 +1162,34 @@ static NTSTATUS fetch_sam_entry_ldif(TALLOC_CTX *mem_ctx,
                case NETR_DELTA_GROUP:
                        fetch_group_info_to_ldif(mem_ctx,
                                                 u.group,
-                                                &l->groupmap[*g_index],
+                                                &l->groupmap[*g_index_p],
                                                 l->add_file,
                                                 ctx->domain_sid_str,
                                                 l->suffix);
-                       (*g_index)++;
+                       (*g_index_p)++;
                        break;
 
                case NETR_DELTA_USER:
                        fetch_account_info_to_ldif(mem_ctx,
                                                   u.user,
                                                   l->groupmap,
-                                                  &l->accountmap[*a_index],
+                                                  &l->accountmap[*a_index_p],
                                                   l->add_file,
                                                   ctx->domain_sid_str,
                                                   l->suffix,
                                                   l->num_alloced);
-                       (*a_index)++;
+                       (*a_index_p)++;
                        break;
 
                case NETR_DELTA_ALIAS:
                        fetch_alias_info_to_ldif(mem_ctx,
                                                 u.alias,
-                                                &l->groupmap[*g_index],
+                                                &l->groupmap[*g_index_p],
                                                 l->add_file,
                                                 ctx->domain_sid_str,
                                                 l->suffix,
                                                 database_id);
-                       (*g_index)++;
+                       (*g_index_p)++;
                        break;
 
                case NETR_DELTA_GROUP_MEMBER:
@@ -1126,12 +1227,12 @@ static NTSTATUS ldif_realloc_maps(TALLOC_CTX *mem_ctx,
                                  uint32_t num_entries)
 {
        /* Re-allocate memory for groupmap and accountmap arrays */
-       l->groupmap = TALLOC_REALLOC_ARRAY(mem_ctx,
+       l->groupmap = talloc_realloc(mem_ctx,
                                           l->groupmap,
                                           GROUPMAP,
                                           num_entries + l->num_alloced);
 
-       l->accountmap = TALLOC_REALLOC_ARRAY(mem_ctx,
+       l->accountmap = talloc_realloc(mem_ctx,
                                             l->accountmap,
                                             ACCOUNTMAP,
                                             num_entries + l->num_alloced);
@@ -1156,15 +1257,12 @@ static NTSTATUS ldif_realloc_maps(TALLOC_CTX *mem_ctx,
 /****************************************************************
 ****************************************************************/
 
-NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
-                               enum netr_SamDatabaseID database_id,
-                               struct netr_DELTA_ENUM_ARRAY *r,
-                               bool last_query,
-                               struct samsync_context *ctx)
+static NTSTATUS init_ldif(TALLOC_CTX *mem_ctx,
+                         struct samsync_context *ctx,
+                         enum netr_SamDatabaseID database_id,
+                         uint64_t *sequence_num)
 {
        NTSTATUS status;
-       int i;
-       uint32_t g_index = 0, a_index = 0;
        struct samsync_ldif_context *ldif_ctx =
                (struct samsync_ldif_context *)ctx->private_data;
 
@@ -1174,11 +1272,28 @@ NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
                                   ctx->domain_sid_str,
                                   &ldif_ctx);
        if (!NT_STATUS_IS_OK(status)) {
-               goto failed;
+               return status;
        }
 
        ctx->private_data = ldif_ctx;
 
+       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,
+                                      uint64_t *sequence_num,
+                                      struct samsync_context *ctx)
+{
+       NTSTATUS status;
+       int i;
+       struct samsync_ldif_context *ldif_ctx =
+               (struct samsync_ldif_context *)ctx->private_data;
+
        status = ldif_realloc_maps(mem_ctx, ldif_ctx, r->num_deltas);
        if (!NT_STATUS_IS_OK(status)) {
                goto failed;
@@ -1193,18 +1308,6 @@ NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
                }
        }
 
-       /* This was the last query */
-       if (last_query) {
-               ldif_write_output(database_id, ldif_ctx);
-               if (ldif_ctx->ldif_file != stdout) {
-                       ctx->result_message = talloc_asprintf(mem_ctx,
-                               "Vampired %d accounts and %d groups to %s",
-                               a_index, g_index, ctx->output_filename);
-               }
-               ldif_free_context(ldif_ctx);
-               ctx->private_data = NULL;
-       }
-
        return NT_STATUS_OK;
 
  failed:
@@ -1214,13 +1317,54 @@ NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
        return status;
 }
 
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS close_ldif(TALLOC_CTX *mem_ctx,
+                          struct samsync_context *ctx,
+                          enum netr_SamDatabaseID database_id,
+                          uint64_t sequence_num)
+{
+       struct samsync_ldif_context *ldif_ctx =
+               (struct samsync_ldif_context *)ctx->private_data;
+
+       /* This was the last query */
+       ldif_write_output(database_id, ldif_ctx);
+       if (ldif_ctx->ldif_file != stdout) {
+               ctx->result_message = talloc_asprintf(ctx,
+                       "Vampired %d accounts and %d groups to %s",
+                       a_index, g_index, ctx->output_filename);
+       }
+
+       ldif_free_context(ldif_ctx);
+       ctx->private_data = NULL;
+
+       return NT_STATUS_OK;
+}
+
 #else /* HAVE_LDAP */
 
-NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
-                               enum netr_SamDatabaseID database_id,
-                               struct netr_DELTA_ENUM_ARRAY *r,
-                               bool last_query,
-                               struct samsync_context *ctx)
+static NTSTATUS init_ldif(TALLOC_CTX *mem_ctx,
+                         struct samsync_context *ctx,
+                         enum netr_SamDatabaseID database_id,
+                         uint64_t *sequence_num)
+{
+       return NT_STATUS_NOT_SUPPORTED;
+}
+
+static NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
+                                      enum netr_SamDatabaseID database_id,
+                                      struct netr_DELTA_ENUM_ARRAY *r,
+                                      uint64_t *sequence_num,
+                                      struct samsync_context *ctx)
+{
+       return NT_STATUS_NOT_SUPPORTED;
+}
+
+static NTSTATUS close_ldif(TALLOC_CTX *mem_ctx,
+                          struct samsync_context *ctx,
+                          enum netr_SamDatabaseID database_id,
+                          uint64_t sequence_num)
 {
        return NT_STATUS_NOT_SUPPORTED;
 }
@@ -1228,5 +1372,7 @@ NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
 #endif
 
 const struct samsync_ops libnet_samsync_ldif_ops = {
+       .startup                = init_ldif,
        .process_objects        = fetch_sam_entries_ldif,
+       .finish                 = close_ldif,
 };