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