s3-libnet-samsync: add samsync_ops to all samsync modules.
[nivanova/samba-autobuild/.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         char *flags, *user_rdn;
580         const char *ou;
581         const char* nopasswd = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
582         uchar zero_buf[16];
583         uint32 rid = 0, group_rid = 0, gidNumber = 0;
584         time_t unix_time;
585         int i;
586
587         memset(zero_buf, '\0', sizeof(zero_buf));
588
589         /* Get the username */
590         fstrcpy(username, r->account_name.string);
591
592         /* Get the rid */
593         rid = r->rid;
594
595         /* Map the rid and username for group member info later */
596         accountmap->rid = rid;
597         accountmap->cn = talloc_strdup(mem_ctx, username);
598         NT_STATUS_HAVE_NO_MEMORY(accountmap->cn);
599
600         /* Get the home directory */
601         if (r->acct_flags & ACB_NORMAL) {
602                 fstrcpy(homedir, r->home_directory.string);
603                 if (!*homedir) {
604                         snprintf(homedir, sizeof(homedir), "/home/%s", username);
605                 } else {
606                         snprintf(homedir, sizeof(homedir), "/nobodyshomedir");
607                 }
608                 ou = lp_ldap_user_suffix();
609         } else {
610                 ou = lp_ldap_machine_suffix();
611                 snprintf(homedir, sizeof(homedir), "/machinehomedir");
612         }
613
614         /* Get the logon script */
615         fstrcpy(logonscript, r->logon_script.string);
616
617         /* Get the home drive */
618         fstrcpy(homedrive, r->home_drive.string);
619
620         /* Get the home path */
621         fstrcpy(homepath, r->home_directory.string);
622
623         /* Get the description */
624         fstrcpy(description, r->description.string);
625
626         /* Get the display name */
627         fstrcpy(fullname, r->full_name.string);
628
629         /* Get the profile path */
630         fstrcpy(profilepath, r->profile_path.string);
631
632         /* Get lm and nt password data */
633         if (memcmp(r->lmpassword.hash, zero_buf, 16) != 0) {
634                 pdb_sethexpwd(hex_lm_passwd, r->lmpassword.hash, 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                 pdb_sethexpwd(hex_nt_passwd, r->ntpassword.hash, r->acct_flags);
640         } else {
641                 pdb_sethexpwd(hex_nt_passwd, NULL, 0);
642         }
643         unix_time = nt_time_to_unix(r->last_password_change);
644
645         /* Increment the uid for the new user */
646         ldif_uid++;
647
648         /* Set up group id and sambaSID for the user */
649         group_rid = r->primary_gid;
650         for (i=0; i<alloced; i++) {
651                 if (groupmap[i].rid == group_rid) break;
652         }
653         if (i == alloced){
654                 DEBUG(1, ("Could not find rid %d in groupmap array\n",
655                           group_rid));
656                 return NT_STATUS_UNSUCCESSFUL;
657         }
658         gidNumber = groupmap[i].gidNumber;
659         snprintf(sambaSID, sizeof(sambaSID), groupmap[i].sambaSID);
660
661         /* Set up sambaAcctFlags */
662         flags = pdb_encode_acct_ctrl(r->acct_flags,
663                                      NEW_PW_FORMAT_SPACE_PADDED_LEN);
664
665         /* Add the user to the temporary add ldif file */
666         /* this isn't quite right...we can't assume there's just OU=. jmcd */
667         user_rdn = sstring_sub(ou, '=', ',');
668         fprintf(add_fd, "# %s, %s, %s\n", username, user_rdn, suffix);
669         fprintf_attr(add_fd, "dn", "uid=%s,ou=%s,%s", username, user_rdn,
670                      suffix);
671         SAFE_FREE(user_rdn);
672         fprintf(add_fd, "ObjectClass: top\n");
673         fprintf(add_fd, "objectClass: inetOrgPerson\n");
674         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXACCOUNT);
675         fprintf(add_fd, "objectClass: shadowAccount\n");
676         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_SAMBASAMACCOUNT);
677         fprintf_attr(add_fd, "cn", "%s", username);
678         fprintf_attr(add_fd, "sn", "%s", username);
679         fprintf_attr(add_fd, "uid", "%s", username);
680         fprintf(add_fd, "uidNumber: %d\n", ldif_uid);
681         fprintf(add_fd, "gidNumber: %d\n", gidNumber);
682         fprintf_attr(add_fd, "homeDirectory", "%s", homedir);
683         if (*homepath)
684                 fprintf_attr(add_fd, "sambaHomePath", "%s", homepath);
685         if (*homedrive)
686                 fprintf_attr(add_fd, "sambaHomeDrive", "%s", homedrive);
687         if (*logonscript)
688                 fprintf_attr(add_fd, "sambaLogonScript", "%s", logonscript);
689         fprintf(add_fd, "loginShell: %s\n",
690                 ((r->acct_flags & ACB_NORMAL) ?
691                  "/bin/bash" : "/bin/false"));
692         fprintf(add_fd, "gecos: System User\n");
693         if (*description)
694                 fprintf_attr(add_fd, "description", "%s", description);
695         fprintf(add_fd, "sambaSID: %s-%d\n", sid, rid);
696         fprintf(add_fd, "sambaPrimaryGroupSID: %s\n", sambaSID);
697         if(*fullname)
698                 fprintf_attr(add_fd, "displayName", "%s", fullname);
699         if(*profilepath)
700                 fprintf_attr(add_fd, "sambaProfilePath", "%s", profilepath);
701         if (strcmp(nopasswd, hex_lm_passwd) != 0)
702                 fprintf(add_fd, "sambaLMPassword: %s\n", hex_lm_passwd);
703         if (strcmp(nopasswd, hex_nt_passwd) != 0)
704                 fprintf(add_fd, "sambaNTPassword: %s\n", hex_nt_passwd);
705         fprintf(add_fd, "sambaPwdLastSet: %d\n", (int)unix_time);
706         fprintf(add_fd, "sambaAcctFlags: %s\n", flags);
707         fprintf(add_fd, "\n");
708         fflush(add_fd);
709
710         /* Return */
711         return NT_STATUS_OK;
712 }
713
714 /****************************************************************
715 ****************************************************************/
716
717 static NTSTATUS fetch_alias_info_to_ldif(TALLOC_CTX *mem_ctx,
718                                          struct netr_DELTA_ALIAS *r,
719                                          GROUPMAP *groupmap,
720                                          FILE *add_fd,
721                                          const char *sid,
722                                          const char *suffix,
723                                          enum netr_SamDatabaseID database_id)
724 {
725         fstring aliasname, description;
726         uint32 grouptype = 0, g_rid = 0;
727         char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
728
729         /* Get the alias name */
730         fstrcpy(aliasname, r->alias_name.string);
731
732         /* Get the alias description */
733         fstrcpy(description, r->description.string);
734
735         /* Set up the group type */
736         switch (database_id) {
737         case SAM_DATABASE_DOMAIN:
738                 grouptype = 4;
739                 break;
740         case SAM_DATABASE_BUILTIN:
741                 grouptype = 5;
742                 break;
743         default:
744                 grouptype = 4;
745                 break;
746         }
747
748         /*
749           These groups are entered by populate_ldap_for_ldif
750           Note that populate creates a group called Relicators,
751           but NT returns a group called Replicator
752         */
753         if (strcmp(aliasname, "Domain Admins") == 0 ||
754             strcmp(aliasname, "Domain Users") == 0 ||
755             strcmp(aliasname, "Domain Guests") == 0 ||
756             strcmp(aliasname, "Domain Computers") == 0 ||
757             strcmp(aliasname, "Administrators") == 0 ||
758             strcmp(aliasname, "Print Operators") == 0 ||
759             strcmp(aliasname, "Backup Operators") == 0 ||
760             strcmp(aliasname, "Replicator") == 0) {
761                 SAFE_FREE(group_attr);
762                 return NT_STATUS_OK;
763         } else {
764                 /* Increment the gid for the new group */
765                 ldif_gid++;
766         }
767
768         /* Map the group rid and gid */
769         g_rid = r->rid;
770         groupmap->gidNumber = ldif_gid;
771         groupmap->sambaSID = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
772         NT_STATUS_HAVE_NO_MEMORY(groupmap->sambaSID);
773
774         /* Write the data to the temporary add ldif file */
775         fprintf(add_fd, "# %s, %s, %s\n", aliasname, group_attr,
776                 suffix);
777         fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", aliasname, group_attr,
778                      suffix);
779         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
780         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
781         fprintf(add_fd, "cn: %s\n", aliasname);
782         fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
783         fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
784         fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
785         fprintf_attr(add_fd, "displayName", "%s", aliasname);
786         if (description[0])
787                 fprintf_attr(add_fd, "description", "%s", description);
788         fprintf(add_fd, "\n");
789         fflush(add_fd);
790
791         SAFE_FREE(group_attr);
792         /* Return */
793         return NT_STATUS_OK;
794 }
795
796 /****************************************************************
797 ****************************************************************/
798
799 static NTSTATUS fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER *r,
800                                             uint32_t id_rid,
801                                             GROUPMAP *groupmap,
802                                             ACCOUNTMAP *accountmap,
803                                             FILE *mod_fd, int alloced)
804 {
805         fstring group_dn;
806         uint32 group_rid = 0, rid = 0;
807         int i, j, k;
808
809         /* Get the dn for the group */
810         if (r->num_rids > 0) {
811                 group_rid = id_rid;
812                 for (j=0; j<alloced; j++) {
813                         if (groupmap[j].rid == group_rid) break;
814                 }
815                 if (j == alloced){
816                         DEBUG(1, ("Could not find rid %d in groupmap array\n",
817                                   group_rid));
818                         return NT_STATUS_UNSUCCESSFUL;
819                 }
820                 snprintf(group_dn, sizeof(group_dn), "%s", groupmap[j].group_dn);
821                 fprintf(mod_fd, "dn: %s\n", group_dn);
822
823                 /* Get the cn for each member */
824                 for (i=0; i < r->num_rids; i++) {
825                         rid = r->rids[i];
826                         for (k=0; k<alloced; k++) {
827                                 if (accountmap[k].rid == rid) break;
828                         }
829                         if (k == alloced){
830                                 DEBUG(1, ("Could not find rid %d in "
831                                           "accountmap array\n", rid));
832                                 return NT_STATUS_UNSUCCESSFUL;
833                         }
834                         fprintf(mod_fd, "memberUid: %s\n", accountmap[k].cn);
835                 }
836                 fprintf(mod_fd, "\n");
837         }
838         fflush(mod_fd);
839
840         /* Return */
841         return NT_STATUS_OK;
842 }
843
844 /****************************************************************
845 ****************************************************************/
846
847 static NTSTATUS ldif_init_context(TALLOC_CTX *mem_ctx,
848                                   enum netr_SamDatabaseID database_id,
849                                   const char *ldif_filename,
850                                   const char *domain_sid_str,
851                                   struct samsync_ldif_context **ctx)
852 {
853         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
854         struct samsync_ldif_context *r;
855         const char *add_template = "/tmp/add.ldif.XXXXXX";
856         const char *mod_template = "/tmp/mod.ldif.XXXXXX";
857         const char *builtin_sid = "S-1-5-32";
858
859         /* Get other smb.conf data */
860         if (!(lp_workgroup()) || !*(lp_workgroup())) {
861                 DEBUG(0,("workgroup missing from smb.conf--exiting\n"));
862                 exit(1);
863         }
864
865         /* Get the ldap suffix */
866         if (!(lp_ldap_suffix()) || !*(lp_ldap_suffix())) {
867                 DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
868                 exit(1);
869         }
870
871         if (*ctx && (*ctx)->initialized) {
872                 return NT_STATUS_OK;
873         }
874
875         r = TALLOC_ZERO_P(mem_ctx, struct samsync_ldif_context);
876         NT_STATUS_HAVE_NO_MEMORY(r);
877
878         /* Get the ldap suffix */
879         r->suffix = lp_ldap_suffix();
880
881         /* Ensure we have an output file */
882         if (ldif_filename) {
883                 r->ldif_file = fopen(ldif_filename, "a");
884         } else {
885                 r->ldif_file = stdout;
886         }
887
888         if (!r->ldif_file) {
889                 fprintf(stderr, "Could not open %s\n", ldif_filename);
890                 DEBUG(1, ("Could not open %s\n", ldif_filename));
891                 status = NT_STATUS_UNSUCCESSFUL;
892                 goto done;
893         }
894
895         r->add_template = talloc_strdup(mem_ctx, add_template);
896         r->mod_template = talloc_strdup(mem_ctx, mod_template);
897         if (!r->add_template || !r->mod_template) {
898                 status = NT_STATUS_NO_MEMORY;
899                 goto done;
900         }
901
902         r->add_name = talloc_strdup(mem_ctx, add_template);
903         r->mod_name = talloc_strdup(mem_ctx, mod_template);
904         if (!r->add_name || !r->mod_name) {
905                 status = NT_STATUS_NO_MEMORY;
906                 goto done;
907         }
908
909         /* Open the add and mod ldif files */
910         if (!(r->add_file = fdopen(smb_mkstemp(r->add_name),"w"))) {
911                 DEBUG(1, ("Could not open %s\n", r->add_name));
912                 status = NT_STATUS_UNSUCCESSFUL;
913                 goto done;
914         }
915         if (!(r->mod_file = fdopen(smb_mkstemp(r->mod_name),"w"))) {
916                 DEBUG(1, ("Could not open %s\n", r->mod_name));
917                 status = NT_STATUS_UNSUCCESSFUL;
918                 goto done;
919         }
920
921         /* Allocate initial memory for groupmap and accountmap arrays */
922         r->groupmap = TALLOC_ZERO_ARRAY(mem_ctx, GROUPMAP, 8);
923         r->accountmap = TALLOC_ZERO_ARRAY(mem_ctx, ACCOUNTMAP, 8);
924         if (r->groupmap == NULL || r->accountmap == NULL) {
925                 DEBUG(1,("GROUPMAP talloc failed\n"));
926                 status = NT_STATUS_NO_MEMORY;
927                 goto done;
928         }
929
930         /* Remember how many we malloced */
931         r->num_alloced = 8;
932
933         /* Initial database population */
934         if (database_id == SAM_DATABASE_DOMAIN) {
935
936                 status = populate_ldap_for_ldif(domain_sid_str,
937                                                 r->suffix,
938                                                 builtin_sid,
939                                                 r->add_file);
940                 if (!NT_STATUS_IS_OK(status)) {
941                         goto done;
942                 }
943
944                 status = map_populate_groups(mem_ctx,
945                                              r->groupmap,
946                                              r->accountmap,
947                                              domain_sid_str,
948                                              r->suffix,
949                                              builtin_sid);
950                 if (!NT_STATUS_IS_OK(status)) {
951                         goto done;
952                 }
953         }
954
955         r->initialized = true;
956
957         *ctx = r;
958
959         return NT_STATUS_OK;
960  done:
961         TALLOC_FREE(r);
962         return status;
963 }
964
965 /****************************************************************
966 ****************************************************************/
967
968 static void ldif_free_context(struct samsync_ldif_context *r)
969 {
970         if (!r) {
971                 return;
972         }
973
974         /* Close and delete the ldif files */
975         if (r->add_file) {
976                 fclose(r->add_file);
977         }
978
979         if ((r->add_name != NULL) &&
980             strcmp(r->add_name, r->add_template) && (unlink(r->add_name))) {
981                 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
982                          r->add_name, strerror(errno)));
983         }
984
985         if (r->mod_file) {
986                 fclose(r->mod_file);
987         }
988
989         if ((r->mod_name != NULL) &&
990             strcmp(r->mod_name, r->mod_template) && (unlink(r->mod_name))) {
991                 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
992                          r->mod_name, strerror(errno)));
993         }
994
995         if (r->ldif_file && (r->ldif_file != stdout)) {
996                 fclose(r->ldif_file);
997         }
998
999         TALLOC_FREE(r);
1000 }
1001
1002 /****************************************************************
1003 ****************************************************************/
1004
1005 static void ldif_write_output(enum netr_SamDatabaseID database_id,
1006                               struct samsync_ldif_context *l)
1007 {
1008         /* Write ldif data to the user's file */
1009         if (database_id == SAM_DATABASE_DOMAIN) {
1010                 fprintf(l->ldif_file,
1011                         "# SAM_DATABASE_DOMAIN: ADD ENTITIES\n");
1012                 fprintf(l->ldif_file,
1013                         "# =================================\n\n");
1014                 fflush(l->ldif_file);
1015         } else if (database_id == SAM_DATABASE_BUILTIN) {
1016                 fprintf(l->ldif_file,
1017                         "# SAM_DATABASE_BUILTIN: ADD ENTITIES\n");
1018                 fprintf(l->ldif_file,
1019                         "# ==================================\n\n");
1020                 fflush(l->ldif_file);
1021         }
1022         fseek(l->add_file, 0, SEEK_SET);
1023         transfer_file(fileno(l->add_file), fileno(l->ldif_file), (size_t) -1);
1024
1025         if (database_id == SAM_DATABASE_DOMAIN) {
1026                 fprintf(l->ldif_file,
1027                         "# SAM_DATABASE_DOMAIN: MODIFY ENTITIES\n");
1028                 fprintf(l->ldif_file,
1029                         "# ====================================\n\n");
1030                 fflush(l->ldif_file);
1031         } else if (database_id == SAM_DATABASE_BUILTIN) {
1032                 fprintf(l->ldif_file,
1033                         "# SAM_DATABASE_BUILTIN: MODIFY ENTITIES\n");
1034                 fprintf(l->ldif_file,
1035                         "# =====================================\n\n");
1036                 fflush(l->ldif_file);
1037         }
1038         fseek(l->mod_file, 0, SEEK_SET);
1039         transfer_file(fileno(l->mod_file), fileno(l->ldif_file), (size_t) -1);
1040 }
1041
1042 /****************************************************************
1043 ****************************************************************/
1044
1045 static NTSTATUS fetch_sam_entry_ldif(TALLOC_CTX *mem_ctx,
1046                                      enum netr_SamDatabaseID database_id,
1047                                      struct netr_DELTA_ENUM *r,
1048                                      struct samsync_context *ctx,
1049                                      uint32_t *a_index,
1050                                      uint32_t *g_index)
1051 {
1052         union netr_DELTA_UNION u = r->delta_union;
1053         union netr_DELTA_ID_UNION id = r->delta_id_union;
1054         struct samsync_ldif_context *l =
1055                 talloc_get_type_abort(ctx->private_data, struct samsync_ldif_context);
1056
1057         switch (r->delta_type) {
1058                 case NETR_DELTA_DOMAIN:
1059                         break;
1060
1061                 case NETR_DELTA_GROUP:
1062                         fetch_group_info_to_ldif(mem_ctx,
1063                                                  u.group,
1064                                                  &l->groupmap[*g_index],
1065                                                  l->add_file,
1066                                                  ctx->domain_sid_str,
1067                                                  l->suffix);
1068                         (*g_index)++;
1069                         break;
1070
1071                 case NETR_DELTA_USER:
1072                         fetch_account_info_to_ldif(mem_ctx,
1073                                                    u.user,
1074                                                    l->groupmap,
1075                                                    &l->accountmap[*a_index],
1076                                                    l->add_file,
1077                                                    ctx->domain_sid_str,
1078                                                    l->suffix,
1079                                                    l->num_alloced);
1080                         (*a_index)++;
1081                         break;
1082
1083                 case NETR_DELTA_ALIAS:
1084                         fetch_alias_info_to_ldif(mem_ctx,
1085                                                  u.alias,
1086                                                  &l->groupmap[*g_index],
1087                                                  l->add_file,
1088                                                  ctx->domain_sid_str,
1089                                                  l->suffix,
1090                                                  database_id);
1091                         (*g_index)++;
1092                         break;
1093
1094                 case NETR_DELTA_GROUP_MEMBER:
1095                         fetch_groupmem_info_to_ldif(u.group_member,
1096                                                     id.rid,
1097                                                     l->groupmap,
1098                                                     l->accountmap,
1099                                                     l->mod_file,
1100                                                     l->num_alloced);
1101                         break;
1102
1103                 case NETR_DELTA_ALIAS_MEMBER:
1104                 case NETR_DELTA_POLICY:
1105                 case NETR_DELTA_ACCOUNT:
1106                 case NETR_DELTA_TRUSTED_DOMAIN:
1107                 case NETR_DELTA_SECRET:
1108                 case NETR_DELTA_RENAME_GROUP:
1109                 case NETR_DELTA_RENAME_USER:
1110                 case NETR_DELTA_RENAME_ALIAS:
1111                 case NETR_DELTA_DELETE_GROUP:
1112                 case NETR_DELTA_DELETE_USER:
1113                 case NETR_DELTA_MODIFY_COUNT:
1114                 default:
1115                         break;
1116         } /* end of switch */
1117
1118         return NT_STATUS_OK;
1119 }
1120
1121 /****************************************************************
1122 ****************************************************************/
1123
1124 static NTSTATUS ldif_realloc_maps(TALLOC_CTX *mem_ctx,
1125                                   struct samsync_ldif_context *l,
1126                                   uint32_t num_entries)
1127 {
1128         /* Re-allocate memory for groupmap and accountmap arrays */
1129         l->groupmap = TALLOC_REALLOC_ARRAY(mem_ctx,
1130                                            l->groupmap,
1131                                            GROUPMAP,
1132                                            num_entries + l->num_alloced);
1133
1134         l->accountmap = TALLOC_REALLOC_ARRAY(mem_ctx,
1135                                              l->accountmap,
1136                                              ACCOUNTMAP,
1137                                              num_entries + l->num_alloced);
1138
1139         if (l->groupmap == NULL || l->accountmap == NULL) {
1140                 DEBUG(1,("GROUPMAP talloc failed\n"));
1141                 return NT_STATUS_NO_MEMORY;
1142         }
1143
1144         /* Initialize the new records */
1145         memset(&(l->groupmap[l->num_alloced]), 0,
1146                sizeof(GROUPMAP) * num_entries);
1147         memset(&(l->accountmap[l->num_alloced]), 0,
1148                sizeof(ACCOUNTMAP) * num_entries);
1149
1150         /* Remember how many we alloced this time */
1151         l->num_alloced += num_entries;
1152
1153         return NT_STATUS_OK;
1154 }
1155
1156 /****************************************************************
1157 ****************************************************************/
1158
1159 NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
1160                                 enum netr_SamDatabaseID database_id,
1161                                 struct netr_DELTA_ENUM_ARRAY *r,
1162                                 bool last_query,
1163                                 struct samsync_context *ctx)
1164 {
1165         NTSTATUS status;
1166         int i;
1167         uint32_t g_index = 0, a_index = 0;
1168         struct samsync_ldif_context *ldif_ctx =
1169                 (struct samsync_ldif_context *)ctx->private_data;
1170
1171         status = ldif_init_context(mem_ctx,
1172                                    database_id,
1173                                    ctx->output_filename,
1174                                    ctx->domain_sid_str,
1175                                    &ldif_ctx);
1176         if (!NT_STATUS_IS_OK(status)) {
1177                 goto failed;
1178         }
1179
1180         ctx->private_data = ldif_ctx;
1181
1182         status = ldif_realloc_maps(mem_ctx, ldif_ctx, r->num_deltas);
1183         if (!NT_STATUS_IS_OK(status)) {
1184                 goto failed;
1185         }
1186
1187         for (i = 0; i < r->num_deltas; i++) {
1188                 status = fetch_sam_entry_ldif(mem_ctx, database_id,
1189                                               &r->delta_enum[i], ctx,
1190                                               &a_index, &g_index);
1191                 if (!NT_STATUS_IS_OK(status)) {
1192                         goto failed;
1193                 }
1194         }
1195
1196         /* This was the last query */
1197         if (last_query) {
1198                 ldif_write_output(database_id, ldif_ctx);
1199                 if (ldif_ctx->ldif_file != stdout) {
1200                         ctx->result_message = talloc_asprintf(mem_ctx,
1201                                 "Vampired %d accounts and %d groups to %s",
1202                                 a_index, g_index, ctx->output_filename);
1203                 }
1204                 ldif_free_context(ldif_ctx);
1205                 ctx->private_data = NULL;
1206         }
1207
1208         return NT_STATUS_OK;
1209
1210  failed:
1211         ldif_free_context(ldif_ctx);
1212         ctx->private_data = NULL;
1213
1214         return status;
1215 }
1216
1217 #else /* HAVE_LDAP */
1218
1219 NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
1220                                 enum netr_SamDatabaseID database_id,
1221                                 struct netr_DELTA_ENUM_ARRAY *r,
1222                                 bool last_query,
1223                                 struct samsync_context *ctx)
1224 {
1225         return NT_STATUS_NOT_SUPPORTED;
1226 }
1227
1228 #endif
1229
1230 const struct samsync_ops libnet_samsync_ldif_ops = {
1231         .process_objects        = fetch_sam_entries_ldif,
1232 };