net_vampire: fix included header.
[metze/samba/wip.git] / source3 / libnet / libnet_samsync_ldif.c
1 /*
2    Unix SMB/CIFS implementation.
3    dump the remote SAM using rpc samsync operations
4
5    Copyright (C) Andrew Tridgell 2002
6    Copyright (C) Tim Potter 2001,2002
7    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
8    Modified by Volker Lendecke 2002
9    Copyright (C) Jeremy Allison 2005.
10    Copyright (C) Guenther Deschner 2008.
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "libnet/libnet_samsync.h"
28
29 /* uid's and gid's for writing deltas to ldif */
30 static uint32 ldif_gid = 999;
31 static uint32 ldif_uid = 999;
32
33 /* Structure for mapping accounts to groups */
34 /* Array element is the group rid */
35 typedef struct _groupmap {
36         uint32_t rid;
37         uint32_t gidNumber;
38         const char *sambaSID;
39         const char *group_dn;
40 } GROUPMAP;
41
42 typedef struct _accountmap {
43         uint32_t rid;
44         const char *cn;
45 } ACCOUNTMAP;
46
47 struct samsync_ldif_context {
48         GROUPMAP *groupmap;
49         ACCOUNTMAP *accountmap;
50         bool initialized;
51         const char *add_template;
52         const char *mod_template;
53         char *add_name;
54         char *mod_name;
55         FILE *add_file;
56         FILE *mod_file;
57         FILE *ldif_file;
58         const char *suffix;
59         int num_alloced;
60 };
61
62 /****************************************************************
63 ****************************************************************/
64
65 static NTSTATUS populate_ldap_for_ldif(const char *sid,
66                                        const char *suffix,
67                                        const char *builtin_sid,
68                                        FILE *add_fd)
69 {
70         const char *user_suffix, *group_suffix, *machine_suffix, *idmap_suffix;
71         char *user_attr=NULL, *group_attr=NULL;
72         char *suffix_attr;
73         int len;
74
75         /* Get the suffix attribute */
76         suffix_attr = sstring_sub(suffix, '=', ',');
77         if (suffix_attr == NULL) {
78                 len = strlen(suffix);
79                 suffix_attr = (char*)SMB_MALLOC(len+1);
80                 memcpy(suffix_attr, suffix, len);
81                 suffix_attr[len] = '\0';
82         }
83
84         /* Write the base */
85         fprintf(add_fd, "# %s\n", suffix);
86         fprintf(add_fd, "dn: %s\n", suffix);
87         fprintf(add_fd, "objectClass: dcObject\n");
88         fprintf(add_fd, "objectClass: organization\n");
89         fprintf(add_fd, "o: %s\n", suffix_attr);
90         fprintf(add_fd, "dc: %s\n", suffix_attr);
91         fprintf(add_fd, "\n");
92         fflush(add_fd);
93
94         user_suffix = lp_ldap_user_suffix();
95         if (user_suffix == NULL) {
96                 SAFE_FREE(suffix_attr);
97                 return NT_STATUS_NO_MEMORY;
98         }
99         /* If it exists and is distinct from other containers,
100            Write the Users entity */
101         if (*user_suffix && strcmp(user_suffix, suffix)) {
102                 user_attr = sstring_sub(lp_ldap_user_suffix(), '=', ',');
103                 fprintf(add_fd, "# %s\n", user_suffix);
104                 fprintf(add_fd, "dn: %s\n", user_suffix);
105                 fprintf(add_fd, "objectClass: organizationalUnit\n");
106                 fprintf(add_fd, "ou: %s\n", user_attr);
107                 fprintf(add_fd, "\n");
108                 fflush(add_fd);
109         }
110
111
112         group_suffix = lp_ldap_group_suffix();
113         if (group_suffix == NULL) {
114                 SAFE_FREE(suffix_attr);
115                 SAFE_FREE(user_attr);
116                 return NT_STATUS_NO_MEMORY;
117         }
118         /* If it exists and is distinct from other containers,
119            Write the Groups entity */
120         if (*group_suffix && strcmp(group_suffix, suffix)) {
121                 group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
122                 fprintf(add_fd, "# %s\n", group_suffix);
123                 fprintf(add_fd, "dn: %s\n", group_suffix);
124                 fprintf(add_fd, "objectClass: organizationalUnit\n");
125                 fprintf(add_fd, "ou: %s\n", group_attr);
126                 fprintf(add_fd, "\n");
127                 fflush(add_fd);
128         }
129
130         /* If it exists and is distinct from other containers,
131            Write the Computers entity */
132         machine_suffix = lp_ldap_machine_suffix();
133         if (machine_suffix == NULL) {
134                 SAFE_FREE(suffix_attr);
135                 SAFE_FREE(user_attr);
136                 SAFE_FREE(group_attr);
137                 return NT_STATUS_NO_MEMORY;
138         }
139         if (*machine_suffix && strcmp(machine_suffix, user_suffix) &&
140             strcmp(machine_suffix, suffix)) {
141                 char *machine_ou = NULL;
142                 fprintf(add_fd, "# %s\n", machine_suffix);
143                 fprintf(add_fd, "dn: %s\n", machine_suffix);
144                 fprintf(add_fd, "objectClass: organizationalUnit\n");
145                 /* this isn't totally correct as it assumes that
146                    there _must_ be an ou. just fixing memleak now. jmcd */
147                 machine_ou = sstring_sub(lp_ldap_machine_suffix(), '=', ',');
148                 fprintf(add_fd, "ou: %s\n", machine_ou);
149                 SAFE_FREE(machine_ou);
150                 fprintf(add_fd, "\n");
151                 fflush(add_fd);
152         }
153
154         /* If it exists and is distinct from other containers,
155            Write the IdMap entity */
156         idmap_suffix = lp_ldap_idmap_suffix();
157         if (idmap_suffix == NULL) {
158                 SAFE_FREE(suffix_attr);
159                 SAFE_FREE(user_attr);
160                 SAFE_FREE(group_attr);
161                 return NT_STATUS_NO_MEMORY;
162         }
163         if (*idmap_suffix &&
164             strcmp(idmap_suffix, user_suffix) &&
165             strcmp(idmap_suffix, suffix)) {
166                 char *s;
167                 fprintf(add_fd, "# %s\n", idmap_suffix);
168                 fprintf(add_fd, "dn: %s\n", idmap_suffix);
169                 fprintf(add_fd, "ObjectClass: organizationalUnit\n");
170                 s = sstring_sub(lp_ldap_idmap_suffix(), '=', ',');
171                 fprintf(add_fd, "ou: %s\n", s);
172                 SAFE_FREE(s);
173                 fprintf(add_fd, "\n");
174                 fflush(add_fd);
175         }
176
177         /* Write the domain entity */
178         fprintf(add_fd, "# %s, %s\n", lp_workgroup(), suffix);
179         fprintf(add_fd, "dn: sambaDomainName=%s,%s\n", lp_workgroup(),
180                 suffix);
181         fprintf(add_fd, "objectClass: sambaDomain\n");
182         fprintf(add_fd, "objectClass: sambaUnixIdPool\n");
183         fprintf(add_fd, "sambaDomainName: %s\n", lp_workgroup());
184         fprintf(add_fd, "sambaSID: %s\n", sid);
185         fprintf(add_fd, "uidNumber: %d\n", ++ldif_uid);
186         fprintf(add_fd, "gidNumber: %d\n", ++ldif_gid);
187         fprintf(add_fd, "\n");
188         fflush(add_fd);
189
190         /* Write the Domain Admins entity */
191         fprintf(add_fd, "# Domain Admins, %s, %s\n", group_attr,
192                 suffix);
193         fprintf(add_fd, "dn: cn=Domain Admins,ou=%s,%s\n", group_attr,
194                 suffix);
195         fprintf(add_fd, "objectClass: posixGroup\n");
196         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
197         fprintf(add_fd, "cn: Domain Admins\n");
198         fprintf(add_fd, "memberUid: Administrator\n");
199         fprintf(add_fd, "description: Netbios Domain Administrators\n");
200         fprintf(add_fd, "gidNumber: 512\n");
201         fprintf(add_fd, "sambaSID: %s-512\n", sid);
202         fprintf(add_fd, "sambaGroupType: 2\n");
203         fprintf(add_fd, "displayName: Domain Admins\n");
204         fprintf(add_fd, "\n");
205         fflush(add_fd);
206
207         /* Write the Domain Users entity */
208         fprintf(add_fd, "# Domain Users, %s, %s\n", group_attr,
209                 suffix);
210         fprintf(add_fd, "dn: cn=Domain Users,ou=%s,%s\n", group_attr,
211                 suffix);
212         fprintf(add_fd, "objectClass: posixGroup\n");
213         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
214         fprintf(add_fd, "cn: Domain Users\n");
215         fprintf(add_fd, "description: Netbios Domain Users\n");
216         fprintf(add_fd, "gidNumber: 513\n");
217         fprintf(add_fd, "sambaSID: %s-513\n", sid);
218         fprintf(add_fd, "sambaGroupType: 2\n");
219         fprintf(add_fd, "displayName: Domain Users\n");
220         fprintf(add_fd, "\n");
221         fflush(add_fd);
222
223         /* Write the Domain Guests entity */
224         fprintf(add_fd, "# Domain Guests, %s, %s\n", group_attr,
225                 suffix);
226         fprintf(add_fd, "dn: cn=Domain Guests,ou=%s,%s\n", group_attr,
227                 suffix);
228         fprintf(add_fd, "objectClass: posixGroup\n");
229         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
230         fprintf(add_fd, "cn: Domain Guests\n");
231         fprintf(add_fd, "description: Netbios Domain Guests\n");
232         fprintf(add_fd, "gidNumber: 514\n");
233         fprintf(add_fd, "sambaSID: %s-514\n", sid);
234         fprintf(add_fd, "sambaGroupType: 2\n");
235         fprintf(add_fd, "displayName: Domain Guests\n");
236         fprintf(add_fd, "\n");
237         fflush(add_fd);
238
239         /* Write the Domain Computers entity */
240         fprintf(add_fd, "# Domain Computers, %s, %s\n", group_attr,
241                 suffix);
242         fprintf(add_fd, "dn: cn=Domain Computers,ou=%s,%s\n",
243                 group_attr, suffix);
244         fprintf(add_fd, "objectClass: posixGroup\n");
245         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
246         fprintf(add_fd, "gidNumber: 515\n");
247         fprintf(add_fd, "cn: Domain Computers\n");
248         fprintf(add_fd, "description: Netbios Domain Computers accounts\n");
249         fprintf(add_fd, "sambaSID: %s-515\n", sid);
250         fprintf(add_fd, "sambaGroupType: 2\n");
251         fprintf(add_fd, "displayName: Domain Computers\n");
252         fprintf(add_fd, "\n");
253         fflush(add_fd);
254
255         /* Write the Admininistrators Groups entity */
256         fprintf(add_fd, "# Administrators, %s, %s\n", group_attr,
257                 suffix);
258         fprintf(add_fd, "dn: cn=Administrators,ou=%s,%s\n", group_attr,
259                 suffix);
260         fprintf(add_fd, "objectClass: posixGroup\n");
261         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
262         fprintf(add_fd, "gidNumber: 544\n");
263         fprintf(add_fd, "cn: Administrators\n");
264         fprintf(add_fd, "description: Netbios Domain Members can fully administer the computer/sambaDomainName\n");
265         fprintf(add_fd, "sambaSID: %s-544\n", builtin_sid);
266         fprintf(add_fd, "sambaGroupType: 5\n");
267         fprintf(add_fd, "displayName: Administrators\n");
268         fprintf(add_fd, "\n");
269
270         /* Write the Print Operator entity */
271         fprintf(add_fd, "# Print Operators, %s, %s\n", group_attr,
272                 suffix);
273         fprintf(add_fd, "dn: cn=Print Operators,ou=%s,%s\n",
274                 group_attr, suffix);
275         fprintf(add_fd, "objectClass: posixGroup\n");
276         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
277         fprintf(add_fd, "gidNumber: 550\n");
278         fprintf(add_fd, "cn: Print Operators\n");
279         fprintf(add_fd, "description: Netbios Domain Print Operators\n");
280         fprintf(add_fd, "sambaSID: %s-550\n", builtin_sid);
281         fprintf(add_fd, "sambaGroupType: 5\n");
282         fprintf(add_fd, "displayName: Print Operators\n");
283         fprintf(add_fd, "\n");
284         fflush(add_fd);
285
286         /* Write the Backup Operators entity */
287         fprintf(add_fd, "# Backup Operators, %s, %s\n", group_attr,
288                 suffix);
289         fprintf(add_fd, "dn: cn=Backup Operators,ou=%s,%s\n",
290                 group_attr, suffix);
291         fprintf(add_fd, "objectClass: posixGroup\n");
292         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
293         fprintf(add_fd, "gidNumber: 551\n");
294         fprintf(add_fd, "cn: Backup Operators\n");
295         fprintf(add_fd, "description: Netbios Domain Members can bypass file security to back up files\n");
296         fprintf(add_fd, "sambaSID: %s-551\n", builtin_sid);
297         fprintf(add_fd, "sambaGroupType: 5\n");
298         fprintf(add_fd, "displayName: Backup Operators\n");
299         fprintf(add_fd, "\n");
300         fflush(add_fd);
301
302         /* Write the Replicators entity */
303         fprintf(add_fd, "# Replicators, %s, %s\n", group_attr, suffix);
304         fprintf(add_fd, "dn: cn=Replicators,ou=%s,%s\n", group_attr,
305                 suffix);
306         fprintf(add_fd, "objectClass: posixGroup\n");
307         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
308         fprintf(add_fd, "gidNumber: 552\n");
309         fprintf(add_fd, "cn: Replicators\n");
310         fprintf(add_fd, "description: Netbios Domain Supports file replication in a sambaDomainName\n");
311         fprintf(add_fd, "sambaSID: %s-552\n", builtin_sid);
312         fprintf(add_fd, "sambaGroupType: 5\n");
313         fprintf(add_fd, "displayName: Replicators\n");
314         fprintf(add_fd, "\n");
315         fflush(add_fd);
316
317         /* Deallocate memory, and return */
318         SAFE_FREE(suffix_attr);
319         SAFE_FREE(user_attr);
320         SAFE_FREE(group_attr);
321         return NT_STATUS_OK;
322 }
323
324 /****************************************************************
325 ****************************************************************/
326
327 static NTSTATUS map_populate_groups(TALLOC_CTX *mem_ctx,
328                                     GROUPMAP *groupmap,
329                                     ACCOUNTMAP *accountmap,
330                                     const char *sid,
331                                     const char *suffix,
332                                     const char *builtin_sid)
333 {
334         char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
335
336         /* Map the groups created by populate_ldap_for_ldif */
337         groupmap[0].rid         = 512;
338         groupmap[0].gidNumber   = 512;
339         groupmap[0].sambaSID    = talloc_asprintf(mem_ctx, "%s-512", sid);
340         groupmap[0].group_dn    = talloc_asprintf(mem_ctx,
341                 "cn=Domain Admins,ou=%s,%s", group_attr, suffix);
342         NT_STATUS_HAVE_NO_MEMORY(groupmap[0].sambaSID);
343         NT_STATUS_HAVE_NO_MEMORY(groupmap[0].group_dn);
344
345         accountmap[0].rid       = 512;
346         accountmap[0].cn        = talloc_strdup(mem_ctx, "Domain Admins");
347         NT_STATUS_HAVE_NO_MEMORY(accountmap[0].cn);
348
349         groupmap[1].rid         = 513;
350         groupmap[1].gidNumber   = 513;
351         groupmap[1].sambaSID    = talloc_asprintf(mem_ctx, "%s-513", sid);
352         groupmap[1].group_dn    = talloc_asprintf(mem_ctx,
353                 "cn=Domain Users,ou=%s,%s", group_attr, suffix);
354         NT_STATUS_HAVE_NO_MEMORY(groupmap[1].sambaSID);
355         NT_STATUS_HAVE_NO_MEMORY(groupmap[1].group_dn);
356
357         accountmap[1].rid       = 513;
358         accountmap[1].cn        = talloc_strdup(mem_ctx, "Domain Users");
359         NT_STATUS_HAVE_NO_MEMORY(accountmap[1].cn);
360
361         groupmap[2].rid         = 514;
362         groupmap[2].gidNumber   = 514;
363         groupmap[2].sambaSID    = talloc_asprintf(mem_ctx, "%s-514", sid);
364         groupmap[2].group_dn    = talloc_asprintf(mem_ctx,
365                 "cn=Domain Guests,ou=%s,%s", group_attr, suffix);
366         NT_STATUS_HAVE_NO_MEMORY(groupmap[2].sambaSID);
367         NT_STATUS_HAVE_NO_MEMORY(groupmap[2].group_dn);
368
369         accountmap[2].rid       = 514;
370         accountmap[2].cn        = talloc_strdup(mem_ctx, "Domain Guests");
371         NT_STATUS_HAVE_NO_MEMORY(accountmap[2].cn);
372
373         groupmap[3].rid         = 515;
374         groupmap[3].gidNumber   = 515;
375         groupmap[3].sambaSID    = talloc_asprintf(mem_ctx, "%s-515", sid);
376         groupmap[3].group_dn    = talloc_asprintf(mem_ctx,
377                 "cn=Domain Computers,ou=%s,%s", group_attr, suffix);
378         NT_STATUS_HAVE_NO_MEMORY(groupmap[3].sambaSID);
379         NT_STATUS_HAVE_NO_MEMORY(groupmap[3].group_dn);
380
381         accountmap[3].rid       = 515;
382         accountmap[3].cn        = talloc_strdup(mem_ctx, "Domain Computers");
383         NT_STATUS_HAVE_NO_MEMORY(accountmap[3].cn);
384
385         groupmap[4].rid         = 544;
386         groupmap[4].gidNumber   = 544;
387         groupmap[4].sambaSID    = talloc_asprintf(mem_ctx, "%s-544", builtin_sid);
388         groupmap[4].group_dn    = talloc_asprintf(mem_ctx,
389                 "cn=Administrators,ou=%s,%s", group_attr, suffix);
390         NT_STATUS_HAVE_NO_MEMORY(groupmap[4].sambaSID);
391         NT_STATUS_HAVE_NO_MEMORY(groupmap[4].group_dn);
392
393         accountmap[4].rid       = 515;
394         accountmap[4].cn        = talloc_strdup(mem_ctx, "Administrators");
395         NT_STATUS_HAVE_NO_MEMORY(accountmap[4].cn);
396
397         groupmap[5].rid         = 550;
398         groupmap[5].gidNumber   = 550;
399         groupmap[5].sambaSID    = talloc_asprintf(mem_ctx, "%s-550", builtin_sid);
400         groupmap[5].group_dn    = talloc_asprintf(mem_ctx,
401                 "cn=Print Operators,ou=%s,%s", group_attr, suffix);
402         NT_STATUS_HAVE_NO_MEMORY(groupmap[5].sambaSID);
403         NT_STATUS_HAVE_NO_MEMORY(groupmap[5].group_dn);
404
405         accountmap[5].rid       = 550;
406         accountmap[5].cn        = talloc_strdup(mem_ctx, "Print Operators");
407         NT_STATUS_HAVE_NO_MEMORY(accountmap[5].cn);
408
409         groupmap[6].rid         = 551;
410         groupmap[6].gidNumber   = 551;
411         groupmap[6].sambaSID    = talloc_asprintf(mem_ctx, "%s-551", builtin_sid);
412         groupmap[6].group_dn    = talloc_asprintf(mem_ctx,
413                 "cn=Backup Operators,ou=%s,%s", group_attr, suffix);
414         NT_STATUS_HAVE_NO_MEMORY(groupmap[6].sambaSID);
415         NT_STATUS_HAVE_NO_MEMORY(groupmap[6].group_dn);
416
417         accountmap[6].rid       = 551;
418         accountmap[6].cn        = talloc_strdup(mem_ctx, "Backup Operators");
419         NT_STATUS_HAVE_NO_MEMORY(accountmap[6].cn);
420
421         groupmap[7].rid         = 552;
422         groupmap[7].gidNumber   = 552;
423         groupmap[7].sambaSID    = talloc_asprintf(mem_ctx, "%s-552", builtin_sid);
424         groupmap[7].group_dn    = talloc_asprintf(mem_ctx,
425                 "cn=Replicators,ou=%s,%s", group_attr, suffix);
426         NT_STATUS_HAVE_NO_MEMORY(groupmap[7].sambaSID);
427         NT_STATUS_HAVE_NO_MEMORY(groupmap[7].group_dn);
428
429         accountmap[7].rid       = 551;
430         accountmap[7].cn        = talloc_strdup(mem_ctx, "Replicators");
431         NT_STATUS_HAVE_NO_MEMORY(accountmap[7].cn);
432
433         SAFE_FREE(group_attr);
434
435         return NT_STATUS_OK;
436 }
437
438 /*
439  * This is a crap routine, but I think it's the quickest way to solve the
440  * UTF8->base64 problem.
441  */
442
443 static int fprintf_attr(FILE *add_fd, const char *attr_name,
444                         const char *fmt, ...)
445 {
446         va_list ap;
447         char *value, *p, *base64;
448         DATA_BLOB base64_blob;
449         bool do_base64 = false;
450         int res;
451
452         va_start(ap, fmt);
453         value = talloc_vasprintf(NULL, fmt, ap);
454         va_end(ap);
455
456         SMB_ASSERT(value != NULL);
457
458         for (p=value; *p; p++) {
459                 if (*p & 0x80) {
460                         do_base64 = true;
461                         break;
462                 }
463         }
464
465         if (!do_base64) {
466                 bool only_whitespace = true;
467                 for (p=value; *p; p++) {
468                         /*
469                          * I know that this not multibyte safe, but we break
470                          * on the first non-whitespace character anyway.
471                          */
472                         if (!isspace(*p)) {
473                                 only_whitespace = false;
474                                 break;
475                         }
476                 }
477                 if (only_whitespace) {
478                         do_base64 = true;
479                 }
480         }
481
482         if (!do_base64) {
483                 res = fprintf(add_fd, "%s: %s\n", attr_name, value);
484                 TALLOC_FREE(value);
485                 return res;
486         }
487
488         base64_blob.data = (unsigned char *)value;
489         base64_blob.length = strlen(value);
490
491         base64 = base64_encode_data_blob(value, base64_blob);
492         SMB_ASSERT(base64 != NULL);
493
494         res = fprintf(add_fd, "%s:: %s\n", attr_name, base64);
495         TALLOC_FREE(value);
496         return res;
497 }
498
499 /****************************************************************
500 ****************************************************************/
501
502 static NTSTATUS fetch_group_info_to_ldif(TALLOC_CTX *mem_ctx,
503                                          struct netr_DELTA_GROUP *r,
504                                          GROUPMAP *groupmap,
505                                          FILE *add_fd,
506                                          const char *sid,
507                                          const char *suffix)
508 {
509         const char *groupname = r->group_name.string;
510         uint32 grouptype = 0, g_rid = 0;
511         char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
512
513         /* Set up the group type (always 2 for group info) */
514         grouptype = 2;
515
516         /* These groups are entered by populate_ldap_for_ldif */
517         if (strcmp(groupname, "Domain Admins") == 0 ||
518             strcmp(groupname, "Domain Users") == 0 ||
519             strcmp(groupname, "Domain Guests") == 0 ||
520             strcmp(groupname, "Domain Computers") == 0 ||
521             strcmp(groupname, "Administrators") == 0 ||
522             strcmp(groupname, "Print Operators") == 0 ||
523             strcmp(groupname, "Backup Operators") == 0 ||
524             strcmp(groupname, "Replicators") == 0) {
525                 SAFE_FREE(group_attr);
526                 return NT_STATUS_OK;
527         } else {
528                 /* Increment the gid for the new group */
529                 ldif_gid++;
530         }
531
532         /* Map the group rid, gid, and dn */
533         g_rid = r->rid;
534         groupmap->rid = g_rid;
535         groupmap->gidNumber = ldif_gid;
536         groupmap->sambaSID      = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
537         groupmap->group_dn      = talloc_asprintf(mem_ctx,
538              "cn=%s,ou=%s,%s", groupname, group_attr, suffix);
539         NT_STATUS_HAVE_NO_MEMORY(groupmap->sambaSID);
540         NT_STATUS_HAVE_NO_MEMORY(groupmap->group_dn);
541
542         /* Write the data to the temporary add ldif file */
543         fprintf(add_fd, "# %s, %s, %s\n", groupname, group_attr,
544                 suffix);
545         fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", groupname, group_attr,
546                      suffix);
547         fprintf(add_fd, "objectClass: posixGroup\n");
548         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
549         fprintf_attr(add_fd, "cn", "%s", groupname);
550         fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
551         fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
552         fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
553         fprintf_attr(add_fd, "displayName", "%s", groupname);
554         fprintf(add_fd, "\n");
555         fflush(add_fd);
556
557         SAFE_FREE(group_attr);
558         /* Return */
559         return NT_STATUS_OK;
560 }
561
562 /****************************************************************
563 ****************************************************************/
564
565 static NTSTATUS fetch_account_info_to_ldif(TALLOC_CTX *mem_ctx,
566                                            struct netr_DELTA_USER *r,
567                                            GROUPMAP *groupmap,
568                                            ACCOUNTMAP *accountmap,
569                                            FILE *add_fd,
570                                            const char *sid,
571                                            const char *suffix,
572                                            int alloced)
573 {
574         fstring username, logonscript, homedrive, homepath = "", homedir = "";
575         fstring hex_nt_passwd, hex_lm_passwd;
576         fstring description, profilepath, fullname, sambaSID;
577         uchar lm_passwd[16], nt_passwd[16];
578         char *flags, *user_rdn;
579         const char *ou;
580         const char* nopasswd = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
581         static uchar zero_buf[16];
582         uint32 rid = 0, group_rid = 0, gidNumber = 0;
583         time_t unix_time;
584         int i;
585
586         /* Get the username */
587         fstrcpy(username, r->account_name.string);
588
589         /* Get the rid */
590         rid = r->rid;
591
592         /* Map the rid and username for group member info later */
593         accountmap->rid = rid;
594         accountmap->cn = talloc_strdup(mem_ctx, username);
595         NT_STATUS_HAVE_NO_MEMORY(accountmap->cn);
596
597         /* Get the home directory */
598         if (r->acct_flags & ACB_NORMAL) {
599                 fstrcpy(homedir, r->home_directory.string);
600                 if (!*homedir) {
601                         snprintf(homedir, sizeof(homedir), "/home/%s", username);
602                 } else {
603                         snprintf(homedir, sizeof(homedir), "/nobodyshomedir");
604                 }
605                 ou = lp_ldap_user_suffix();
606         } else {
607                 ou = lp_ldap_machine_suffix();
608                 snprintf(homedir, sizeof(homedir), "/machinehomedir");
609         }
610
611         /* Get the logon script */
612         fstrcpy(logonscript, r->logon_script.string);
613
614         /* Get the home drive */
615         fstrcpy(homedrive, r->home_drive.string);
616
617         /* Get the home path */
618         fstrcpy(homepath, r->home_directory.string);
619
620         /* Get the description */
621         fstrcpy(description, r->description.string);
622
623         /* Get the display name */
624         fstrcpy(fullname, r->full_name.string);
625
626         /* Get the profile path */
627         fstrcpy(profilepath, r->profile_path.string);
628
629         /* Get lm and nt password data */
630         if (memcmp(r->lmpassword.hash, zero_buf, 16) != 0) {
631                 sam_pwd_hash(r->rid, r->lmpassword.hash, lm_passwd, 0);
632                 pdb_sethexpwd(hex_lm_passwd, lm_passwd, r->acct_flags);
633         } else {
634                 pdb_sethexpwd(hex_lm_passwd, NULL, 0);
635         }
636         if (memcmp(r->ntpassword.hash, zero_buf, 16) != 0) {
637                 sam_pwd_hash(r->rid, r->ntpassword.hash, nt_passwd, 0);
638                 pdb_sethexpwd(hex_nt_passwd, nt_passwd, r->acct_flags);
639         } else {
640                 pdb_sethexpwd(hex_nt_passwd, NULL, 0);
641         }
642         unix_time = nt_time_to_unix(r->last_password_change);
643
644         /* Increment the uid for the new user */
645         ldif_uid++;
646
647         /* Set up group id and sambaSID for the user */
648         group_rid = r->primary_gid;
649         for (i=0; i<alloced; i++) {
650                 if (groupmap[i].rid == group_rid) break;
651         }
652         if (i == alloced){
653                 DEBUG(1, ("Could not find rid %d in groupmap array\n",
654                           group_rid));
655                 return NT_STATUS_UNSUCCESSFUL;
656         }
657         gidNumber = groupmap[i].gidNumber;
658         snprintf(sambaSID, sizeof(sambaSID), groupmap[i].sambaSID);
659
660         /* Set up sambaAcctFlags */
661         flags = pdb_encode_acct_ctrl(r->acct_flags,
662                                      NEW_PW_FORMAT_SPACE_PADDED_LEN);
663
664         /* Add the user to the temporary add ldif file */
665         /* this isn't quite right...we can't assume there's just OU=. jmcd */
666         user_rdn = sstring_sub(ou, '=', ',');
667         fprintf(add_fd, "# %s, %s, %s\n", username, user_rdn, suffix);
668         fprintf_attr(add_fd, "dn", "uid=%s,ou=%s,%s", username, user_rdn,
669                      suffix);
670         SAFE_FREE(user_rdn);
671         fprintf(add_fd, "ObjectClass: top\n");
672         fprintf(add_fd, "objectClass: inetOrgPerson\n");
673         fprintf(add_fd, "objectClass: posixAccount\n");
674         fprintf(add_fd, "objectClass: shadowAccount\n");
675         fprintf(add_fd, "objectClass: sambaSamAccount\n");
676         fprintf_attr(add_fd, "cn", "%s", username);
677         fprintf_attr(add_fd, "sn", "%s", username);
678         fprintf_attr(add_fd, "uid", "%s", username);
679         fprintf(add_fd, "uidNumber: %d\n", ldif_uid);
680         fprintf(add_fd, "gidNumber: %d\n", gidNumber);
681         fprintf_attr(add_fd, "homeDirectory", "%s", homedir);
682         if (*homepath)
683                 fprintf_attr(add_fd, "sambaHomePath", "%s", homepath);
684         if (*homedrive)
685                 fprintf_attr(add_fd, "sambaHomeDrive", "%s", homedrive);
686         if (*logonscript)
687                 fprintf_attr(add_fd, "sambaLogonScript", "%s", logonscript);
688         fprintf(add_fd, "loginShell: %s\n",
689                 ((r->acct_flags & ACB_NORMAL) ?
690                  "/bin/bash" : "/bin/false"));
691         fprintf(add_fd, "gecos: System User\n");
692         if (*description)
693                 fprintf_attr(add_fd, "description", "%s", description);
694         fprintf(add_fd, "sambaSID: %s-%d\n", sid, rid);
695         fprintf(add_fd, "sambaPrimaryGroupSID: %s\n", sambaSID);
696         if(*fullname)
697                 fprintf_attr(add_fd, "displayName", "%s", fullname);
698         if(*profilepath)
699                 fprintf_attr(add_fd, "sambaProfilePath", "%s", profilepath);
700         if (strcmp(nopasswd, hex_lm_passwd) != 0)
701                 fprintf(add_fd, "sambaLMPassword: %s\n", hex_lm_passwd);
702         if (strcmp(nopasswd, hex_nt_passwd) != 0)
703                 fprintf(add_fd, "sambaNTPassword: %s\n", hex_nt_passwd);
704         fprintf(add_fd, "sambaPwdLastSet: %d\n", (int)unix_time);
705         fprintf(add_fd, "sambaAcctFlags: %s\n", flags);
706         fprintf(add_fd, "\n");
707         fflush(add_fd);
708
709         /* Return */
710         return NT_STATUS_OK;
711 }
712
713 /****************************************************************
714 ****************************************************************/
715
716 static NTSTATUS fetch_alias_info_to_ldif(TALLOC_CTX *mem_ctx,
717                                          struct netr_DELTA_ALIAS *r,
718                                          GROUPMAP *groupmap,
719                                          FILE *add_fd,
720                                          const char *sid,
721                                          const char *suffix,
722                                          enum netr_SamDatabaseID database_id)
723 {
724         fstring aliasname, description;
725         uint32 grouptype = 0, g_rid = 0;
726         char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
727
728         /* Get the alias name */
729         fstrcpy(aliasname, r->alias_name.string);
730
731         /* Get the alias description */
732         fstrcpy(description, r->description.string);
733
734         /* Set up the group type */
735         switch (database_id) {
736         case SAM_DATABASE_DOMAIN:
737                 grouptype = 4;
738                 break;
739         case SAM_DATABASE_BUILTIN:
740                 grouptype = 5;
741                 break;
742         default:
743                 grouptype = 4;
744                 break;
745         }
746
747         /*
748           These groups are entered by populate_ldap_for_ldif
749           Note that populate creates a group called Relicators,
750           but NT returns a group called Replicator
751         */
752         if (strcmp(aliasname, "Domain Admins") == 0 ||
753             strcmp(aliasname, "Domain Users") == 0 ||
754             strcmp(aliasname, "Domain Guests") == 0 ||
755             strcmp(aliasname, "Domain Computers") == 0 ||
756             strcmp(aliasname, "Administrators") == 0 ||
757             strcmp(aliasname, "Print Operators") == 0 ||
758             strcmp(aliasname, "Backup Operators") == 0 ||
759             strcmp(aliasname, "Replicator") == 0) {
760                 SAFE_FREE(group_attr);
761                 return NT_STATUS_OK;
762         } else {
763                 /* Increment the gid for the new group */
764                 ldif_gid++;
765         }
766
767         /* Map the group rid and gid */
768         g_rid = r->rid;
769         groupmap->gidNumber = ldif_gid;
770         groupmap->sambaSID = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
771         NT_STATUS_HAVE_NO_MEMORY(groupmap->sambaSID);
772
773         /* Write the data to the temporary add ldif file */
774         fprintf(add_fd, "# %s, %s, %s\n", aliasname, group_attr,
775                 suffix);
776         fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", aliasname, group_attr,
777                      suffix);
778         fprintf(add_fd, "objectClass: posixGroup\n");
779         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
780         fprintf(add_fd, "cn: %s\n", aliasname);
781         fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
782         fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
783         fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
784         fprintf_attr(add_fd, "displayName", "%s", aliasname);
785         if (description[0])
786                 fprintf_attr(add_fd, "description", "%s", description);
787         fprintf(add_fd, "\n");
788         fflush(add_fd);
789
790         SAFE_FREE(group_attr);
791         /* Return */
792         return NT_STATUS_OK;
793 }
794
795 /****************************************************************
796 ****************************************************************/
797
798 static NTSTATUS fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER *r,
799                                             uint32_t id_rid,
800                                             GROUPMAP *groupmap,
801                                             ACCOUNTMAP *accountmap,
802                                             FILE *mod_fd, int alloced)
803 {
804         fstring group_dn;
805         uint32 group_rid = 0, rid = 0;
806         int i, j, k;
807
808         /* Get the dn for the group */
809         if (r->num_rids > 0) {
810                 group_rid = id_rid;
811                 for (j=0; j<alloced; j++) {
812                         if (groupmap[j].rid == group_rid) break;
813                 }
814                 if (j == alloced){
815                         DEBUG(1, ("Could not find rid %d in groupmap array\n",
816                                   group_rid));
817                         return NT_STATUS_UNSUCCESSFUL;
818                 }
819                 snprintf(group_dn, sizeof(group_dn), "%s", groupmap[j].group_dn);
820                 fprintf(mod_fd, "dn: %s\n", group_dn);
821
822                 /* Get the cn for each member */
823                 for (i=0; i < r->num_rids; i++) {
824                         rid = r->rids[i];
825                         for (k=0; k<alloced; k++) {
826                                 if (accountmap[k].rid == rid) break;
827                         }
828                         if (k == alloced){
829                                 DEBUG(1, ("Could not find rid %d in "
830                                           "accountmap array\n", rid));
831                                 return NT_STATUS_UNSUCCESSFUL;
832                         }
833                         fprintf(mod_fd, "memberUid: %s\n", accountmap[k].cn);
834                 }
835                 fprintf(mod_fd, "\n");
836         }
837         fflush(mod_fd);
838
839         /* Return */
840         return NT_STATUS_OK;
841 }
842
843 /****************************************************************
844 ****************************************************************/
845
846 static NTSTATUS ldif_init_context(TALLOC_CTX *mem_ctx,
847                                   enum netr_SamDatabaseID database_id,
848                                   const char *ldif_filename,
849                                   const char *domain_sid_str,
850                                   struct samsync_ldif_context **ctx)
851 {
852         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
853         struct samsync_ldif_context *r;
854         const char *add_template = "/tmp/add.ldif.XXXXXX";
855         const char *mod_template = "/tmp/mod.ldif.XXXXXX";
856         const char *builtin_sid = "S-1-5-32";
857
858         /* Get other smb.conf data */
859         if (!(lp_workgroup()) || !*(lp_workgroup())) {
860                 DEBUG(0,("workgroup missing from smb.conf--exiting\n"));
861                 exit(1);
862         }
863
864         /* Get the ldap suffix */
865         if (!(lp_ldap_suffix()) || !*(lp_ldap_suffix())) {
866                 DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
867                 exit(1);
868         }
869
870         if (*ctx && (*ctx)->initialized) {
871                 return NT_STATUS_OK;
872         }
873
874         r = TALLOC_ZERO_P(mem_ctx, struct samsync_ldif_context);
875         NT_STATUS_HAVE_NO_MEMORY(r);
876
877         /* Get the ldap suffix */
878         r->suffix = lp_ldap_suffix();
879
880         /* Ensure we have an output file */
881         if (ldif_filename) {
882                 r->ldif_file = fopen(ldif_filename, "a");
883         } else {
884                 r->ldif_file = stdout;
885         }
886
887         if (!r->ldif_file) {
888                 fprintf(stderr, "Could not open %s\n", ldif_filename);
889                 DEBUG(1, ("Could not open %s\n", ldif_filename));
890                 status = NT_STATUS_UNSUCCESSFUL;
891                 goto done;
892         }
893
894         r->add_template = talloc_strdup(mem_ctx, add_template);
895         r->mod_template = talloc_strdup(mem_ctx, mod_template);
896         if (!r->add_template || !r->mod_template) {
897                 status = NT_STATUS_NO_MEMORY;
898                 goto done;
899         }
900
901         r->add_name = talloc_strdup(mem_ctx, add_template);
902         r->mod_name = talloc_strdup(mem_ctx, mod_template);
903         if (!r->add_name || !r->mod_name) {
904                 status = NT_STATUS_NO_MEMORY;
905                 goto done;
906         }
907
908         /* Open the add and mod ldif files */
909         if (!(r->add_file = fdopen(smb_mkstemp(r->add_name),"w"))) {
910                 DEBUG(1, ("Could not open %s\n", r->add_name));
911                 status = NT_STATUS_UNSUCCESSFUL;
912                 goto done;
913         }
914         if (!(r->mod_file = fdopen(smb_mkstemp(r->mod_name),"w"))) {
915                 DEBUG(1, ("Could not open %s\n", r->mod_name));
916                 status = NT_STATUS_UNSUCCESSFUL;
917                 goto done;
918         }
919
920         /* Allocate initial memory for groupmap and accountmap arrays */
921         r->groupmap = TALLOC_ZERO_ARRAY(mem_ctx, GROUPMAP, 8);
922         r->accountmap = TALLOC_ZERO_ARRAY(mem_ctx, ACCOUNTMAP, 8);
923         if (r->groupmap == NULL || r->accountmap == NULL) {
924                 DEBUG(1,("GROUPMAP talloc failed\n"));
925                 status = NT_STATUS_NO_MEMORY;
926                 goto done;
927         }
928
929         /* Remember how many we malloced */
930         r->num_alloced = 8;
931
932         /* Initial database population */
933         if (database_id == SAM_DATABASE_DOMAIN) {
934
935                 status = populate_ldap_for_ldif(domain_sid_str,
936                                                 r->suffix,
937                                                 builtin_sid,
938                                                 r->add_file);
939                 if (!NT_STATUS_IS_OK(status)) {
940                         goto done;
941                 }
942
943                 status = map_populate_groups(mem_ctx,
944                                              r->groupmap,
945                                              r->accountmap,
946                                              domain_sid_str,
947                                              r->suffix,
948                                              builtin_sid);
949                 if (!NT_STATUS_IS_OK(status)) {
950                         goto done;
951                 }
952         }
953
954         r->initialized = true;
955
956         *ctx = r;
957
958         return NT_STATUS_OK;
959  done:
960         TALLOC_FREE(r);
961         return status;
962 }
963
964 /****************************************************************
965 ****************************************************************/
966
967 static void ldif_free_context(struct samsync_ldif_context *r)
968 {
969         if (!r) {
970                 return;
971         }
972
973         /* Close and delete the ldif files */
974         if (r->add_file) {
975                 fclose(r->add_file);
976         }
977
978         if ((r->add_name != NULL) &&
979             strcmp(r->add_name, r->add_template) && (unlink(r->add_name))) {
980                 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
981                          r->add_name, strerror(errno)));
982         }
983
984         if (r->mod_file) {
985                 fclose(r->mod_file);
986         }
987
988         if ((r->mod_name != NULL) &&
989             strcmp(r->mod_name, r->mod_template) && (unlink(r->mod_name))) {
990                 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
991                          r->mod_name, strerror(errno)));
992         }
993
994         if (r->ldif_file && (r->ldif_file != stdout)) {
995                 fclose(r->ldif_file);
996         }
997
998         TALLOC_FREE(r);
999 }
1000
1001 /****************************************************************
1002 ****************************************************************/
1003
1004 static void ldif_write_output(enum netr_SamDatabaseID database_id,
1005                               struct samsync_ldif_context *l)
1006 {
1007         /* Write ldif data to the user's file */
1008         if (database_id == SAM_DATABASE_DOMAIN) {
1009                 fprintf(l->ldif_file,
1010                         "# SAM_DATABASE_DOMAIN: ADD ENTITIES\n");
1011                 fprintf(l->ldif_file,
1012                         "# =================================\n\n");
1013                 fflush(l->ldif_file);
1014         } else if (database_id == SAM_DATABASE_BUILTIN) {
1015                 fprintf(l->ldif_file,
1016                         "# SAM_DATABASE_BUILTIN: ADD ENTITIES\n");
1017                 fprintf(l->ldif_file,
1018                         "# ==================================\n\n");
1019                 fflush(l->ldif_file);
1020         }
1021         fseek(l->add_file, 0, SEEK_SET);
1022         transfer_file(fileno(l->add_file), fileno(l->ldif_file), (size_t) -1);
1023
1024         if (database_id == SAM_DATABASE_DOMAIN) {
1025                 fprintf(l->ldif_file,
1026                         "# SAM_DATABASE_DOMAIN: MODIFY ENTITIES\n");
1027                 fprintf(l->ldif_file,
1028                         "# ====================================\n\n");
1029                 fflush(l->ldif_file);
1030         } else if (database_id == SAM_DATABASE_BUILTIN) {
1031                 fprintf(l->ldif_file,
1032                         "# SAM_DATABASE_BUILTIN: MODIFY ENTITIES\n");
1033                 fprintf(l->ldif_file,
1034                         "# =====================================\n\n");
1035                 fflush(l->ldif_file);
1036         }
1037         fseek(l->mod_file, 0, SEEK_SET);
1038         transfer_file(fileno(l->mod_file), fileno(l->ldif_file), (size_t) -1);
1039 }
1040
1041 /****************************************************************
1042 ****************************************************************/
1043
1044 static NTSTATUS fetch_sam_entry_ldif(TALLOC_CTX *mem_ctx,
1045                                      enum netr_SamDatabaseID database_id,
1046                                      struct netr_DELTA_ENUM *r,
1047                                      struct samsync_context *ctx,
1048                                      uint32_t *a_index,
1049                                      uint32_t *g_index)
1050 {
1051         union netr_DELTA_UNION u = r->delta_union;
1052         union netr_DELTA_ID_UNION id = r->delta_id_union;
1053         struct samsync_ldif_context *l =
1054                 talloc_get_type_abort(ctx->private_data, struct samsync_ldif_context);
1055
1056         switch (r->delta_type) {
1057                 case NETR_DELTA_DOMAIN:
1058                         break;
1059
1060                 case NETR_DELTA_GROUP:
1061                         fetch_group_info_to_ldif(mem_ctx,
1062                                                  u.group,
1063                                                  &l->groupmap[*g_index],
1064                                                  l->add_file,
1065                                                  ctx->domain_sid_str,
1066                                                  l->suffix);
1067                         (*g_index)++;
1068                         break;
1069
1070                 case NETR_DELTA_USER:
1071                         fetch_account_info_to_ldif(mem_ctx,
1072                                                    u.user,
1073                                                    l->groupmap,
1074                                                    &l->accountmap[*a_index],
1075                                                    l->add_file,
1076                                                    ctx->domain_sid_str,
1077                                                    l->suffix,
1078                                                    l->num_alloced);
1079                         (*a_index)++;
1080                         break;
1081
1082                 case NETR_DELTA_ALIAS:
1083                         fetch_alias_info_to_ldif(mem_ctx,
1084                                                  u.alias,
1085                                                  &l->groupmap[*g_index],
1086                                                  l->add_file,
1087                                                  ctx->domain_sid_str,
1088                                                  l->suffix,
1089                                                  database_id);
1090                         (*g_index)++;
1091                         break;
1092
1093                 case NETR_DELTA_GROUP_MEMBER:
1094                         fetch_groupmem_info_to_ldif(u.group_member,
1095                                                     id.rid,
1096                                                     l->groupmap,
1097                                                     l->accountmap,
1098                                                     l->mod_file,
1099                                                     l->num_alloced);
1100                         break;
1101
1102                 case NETR_DELTA_ALIAS_MEMBER:
1103                 case NETR_DELTA_POLICY:
1104                 case NETR_DELTA_ACCOUNT:
1105                 case NETR_DELTA_TRUSTED_DOMAIN:
1106                 case NETR_DELTA_SECRET:
1107                 case NETR_DELTA_RENAME_GROUP:
1108                 case NETR_DELTA_RENAME_USER:
1109                 case NETR_DELTA_RENAME_ALIAS:
1110                 case NETR_DELTA_DELETE_GROUP:
1111                 case NETR_DELTA_DELETE_USER:
1112                 case NETR_DELTA_MODIFY_COUNT:
1113                 default:
1114                         break;
1115         } /* end of switch */
1116
1117         return NT_STATUS_OK;
1118 }
1119
1120 /****************************************************************
1121 ****************************************************************/
1122
1123 static NTSTATUS ldif_realloc_maps(TALLOC_CTX *mem_ctx,
1124                                   struct samsync_ldif_context *l,
1125                                   uint32_t num_entries)
1126 {
1127         /* Re-allocate memory for groupmap and accountmap arrays */
1128         l->groupmap = TALLOC_REALLOC_ARRAY(mem_ctx,
1129                                            l->groupmap,
1130                                            GROUPMAP,
1131                                            num_entries + l->num_alloced);
1132
1133         l->accountmap = TALLOC_REALLOC_ARRAY(mem_ctx,
1134                                              l->accountmap,
1135                                              ACCOUNTMAP,
1136                                              num_entries + l->num_alloced);
1137
1138         if (l->groupmap == NULL || l->accountmap == NULL) {
1139                 DEBUG(1,("GROUPMAP talloc failed\n"));
1140                 return NT_STATUS_NO_MEMORY;
1141         }
1142
1143         /* Initialize the new records */
1144         memset(&(l->groupmap[l->num_alloced]), 0,
1145                sizeof(GROUPMAP) * num_entries);
1146         memset(&(l->accountmap[l->num_alloced]), 0,
1147                sizeof(ACCOUNTMAP) * num_entries);
1148
1149         /* Remember how many we alloced this time */
1150         l->num_alloced += num_entries;
1151
1152         return NT_STATUS_OK;
1153 }
1154
1155 /****************************************************************
1156 ****************************************************************/
1157
1158 NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
1159                                 enum netr_SamDatabaseID database_id,
1160                                 struct netr_DELTA_ENUM_ARRAY *r,
1161                                 NTSTATUS result,
1162                                 struct samsync_context *ctx)
1163 {
1164         NTSTATUS status;
1165         int i;
1166         uint32_t g_index = 0, a_index = 0;
1167         struct samsync_ldif_context *ldif_ctx =
1168                 (struct samsync_ldif_context *)ctx->private_data;
1169
1170         status = ldif_init_context(mem_ctx,
1171                                    database_id,
1172                                    ctx->output_filename,
1173                                    ctx->domain_sid_str,
1174                                    &ldif_ctx);
1175         if (!NT_STATUS_IS_OK(status)) {
1176                 goto failed;
1177         }
1178
1179         ctx->private_data = ldif_ctx;
1180
1181         status = ldif_realloc_maps(mem_ctx, ldif_ctx, r->num_deltas);
1182         if (!NT_STATUS_IS_OK(status)) {
1183                 goto failed;
1184         }
1185
1186         for (i = 0; i < r->num_deltas; i++) {
1187                 status = fetch_sam_entry_ldif(mem_ctx, database_id,
1188                                               &r->delta_enum[i], ctx,
1189                                               &a_index, &g_index);
1190                 if (!NT_STATUS_IS_OK(status)) {
1191                         goto failed;
1192                 }
1193         }
1194
1195         /* This was the last query */
1196         if (NT_STATUS_IS_OK(result)) {
1197                 ldif_write_output(database_id, ldif_ctx);
1198                 if (ldif_ctx->ldif_file != stdout) {
1199                         ctx->result_message = talloc_asprintf(mem_ctx,
1200                                 "Vampired %d accounts and %d groups to %s",
1201                                 a_index, g_index, ctx->output_filename);
1202                 }
1203                 ldif_free_context(ldif_ctx);
1204                 ctx->private_data = NULL;
1205         }
1206
1207         return NT_STATUS_OK;
1208
1209  failed:
1210         ldif_free_context(ldif_ctx);
1211         ctx->private_data = NULL;
1212
1213         return status;
1214 }