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