work around AIX6.1 name space pollution rename mod_name to module_name
[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 *module_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         if (groupmap[0].sambaSID == NULL || groupmap[0].group_dn == NULL) {
349                 goto err;
350         }
351
352         accountmap[0].rid       = 512;
353         accountmap[0].cn        = talloc_strdup(mem_ctx, "Domain Admins");
354         if (accountmap[0].cn == NULL) {
355                 goto err;
356         }
357
358         groupmap[1].rid         = 513;
359         groupmap[1].gidNumber   = 513;
360         groupmap[1].sambaSID    = talloc_asprintf(mem_ctx, "%s-513", sid);
361         groupmap[1].group_dn    = talloc_asprintf(mem_ctx,
362                 "cn=Domain Users,ou=%s,%s", group_attr, suffix);
363         if (groupmap[1].sambaSID == NULL || groupmap[1].group_dn == NULL) {
364                 goto err;
365         }
366
367         accountmap[1].rid       = 513;
368         accountmap[1].cn        = talloc_strdup(mem_ctx, "Domain Users");
369         if (accountmap[1].cn == NULL) {
370                 goto err;
371         }
372
373         groupmap[2].rid         = 514;
374         groupmap[2].gidNumber   = 514;
375         groupmap[2].sambaSID    = talloc_asprintf(mem_ctx, "%s-514", sid);
376         groupmap[2].group_dn    = talloc_asprintf(mem_ctx,
377                 "cn=Domain Guests,ou=%s,%s", group_attr, suffix);
378         if (groupmap[2].sambaSID == NULL || groupmap[2].group_dn == NULL) {
379                 goto err;
380         }
381
382         accountmap[2].rid       = 514;
383         accountmap[2].cn        = talloc_strdup(mem_ctx, "Domain Guests");
384         if (accountmap[2].cn == NULL) {
385                 goto err;
386         }
387
388         groupmap[3].rid         = 515;
389         groupmap[3].gidNumber   = 515;
390         groupmap[3].sambaSID    = talloc_asprintf(mem_ctx, "%s-515", sid);
391         groupmap[3].group_dn    = talloc_asprintf(mem_ctx,
392                 "cn=Domain Computers,ou=%s,%s", group_attr, suffix);
393         if (groupmap[3].sambaSID == NULL || groupmap[3].group_dn == NULL) {
394                 goto err;
395         }
396
397         accountmap[3].rid       = 515;
398         accountmap[3].cn        = talloc_strdup(mem_ctx, "Domain Computers");
399         if (accountmap[3].cn == NULL) {
400                 goto err;
401         }
402
403         groupmap[4].rid         = 544;
404         groupmap[4].gidNumber   = 544;
405         groupmap[4].sambaSID    = talloc_asprintf(mem_ctx, "%s-544", builtin_sid);
406         groupmap[4].group_dn    = talloc_asprintf(mem_ctx,
407                 "cn=Administrators,ou=%s,%s", group_attr, suffix);
408         if (groupmap[4].sambaSID == NULL || groupmap[4].group_dn == NULL) {
409                 goto err;
410         }
411
412         accountmap[4].rid       = 515;
413         accountmap[4].cn        = talloc_strdup(mem_ctx, "Administrators");
414         if (accountmap[4].cn == NULL) {
415                 goto err;
416         }
417
418         groupmap[5].rid         = 550;
419         groupmap[5].gidNumber   = 550;
420         groupmap[5].sambaSID    = talloc_asprintf(mem_ctx, "%s-550", builtin_sid);
421         groupmap[5].group_dn    = talloc_asprintf(mem_ctx,
422                 "cn=Print Operators,ou=%s,%s", group_attr, suffix);
423         if (groupmap[5].sambaSID == NULL || groupmap[5].group_dn == NULL) {
424                 goto err;
425         }
426
427         accountmap[5].rid       = 550;
428         accountmap[5].cn        = talloc_strdup(mem_ctx, "Print Operators");
429         if (accountmap[5].cn == NULL) {
430                 goto err;
431         }
432
433         groupmap[6].rid         = 551;
434         groupmap[6].gidNumber   = 551;
435         groupmap[6].sambaSID    = talloc_asprintf(mem_ctx, "%s-551", builtin_sid);
436         groupmap[6].group_dn    = talloc_asprintf(mem_ctx,
437                 "cn=Backup Operators,ou=%s,%s", group_attr, suffix);
438         if (groupmap[6].sambaSID == NULL || groupmap[6].group_dn == NULL) {
439                 goto err;
440         }
441
442         accountmap[6].rid       = 551;
443         accountmap[6].cn        = talloc_strdup(mem_ctx, "Backup Operators");
444         if (accountmap[6].cn == NULL) {
445                 goto err;
446         }
447
448         groupmap[7].rid         = 552;
449         groupmap[7].gidNumber   = 552;
450         groupmap[7].sambaSID    = talloc_asprintf(mem_ctx, "%s-552", builtin_sid);
451         groupmap[7].group_dn    = talloc_asprintf(mem_ctx,
452                 "cn=Replicators,ou=%s,%s", group_attr, suffix);
453         if (groupmap[7].sambaSID == NULL || groupmap[7].group_dn == NULL) {
454                 goto err;
455         }
456
457         accountmap[7].rid       = 551;
458         accountmap[7].cn        = talloc_strdup(mem_ctx, "Replicators");
459         if (accountmap[7].cn == NULL) {
460                 goto err;
461         }
462
463         SAFE_FREE(group_attr);
464
465         return NT_STATUS_OK;
466
467   err:
468
469         SAFE_FREE(group_attr);
470         return NT_STATUS_NO_MEMORY;
471 }
472
473 /*
474  * This is a crap routine, but I think it's the quickest way to solve the
475  * UTF8->base64 problem.
476  */
477
478 static int fprintf_attr(FILE *add_fd, const char *attr_name,
479                         const char *fmt, ...)
480 {
481         va_list ap;
482         char *value, *p, *base64;
483         DATA_BLOB base64_blob;
484         bool do_base64 = false;
485         int res;
486
487         va_start(ap, fmt);
488         value = talloc_vasprintf(NULL, fmt, ap);
489         va_end(ap);
490
491         SMB_ASSERT(value != NULL);
492
493         for (p=value; *p; p++) {
494                 if (*p & 0x80) {
495                         do_base64 = true;
496                         break;
497                 }
498         }
499
500         if (!do_base64) {
501                 bool only_whitespace = true;
502                 for (p=value; *p; p++) {
503                         /*
504                          * I know that this not multibyte safe, but we break
505                          * on the first non-whitespace character anyway.
506                          */
507                         if (!isspace(*p)) {
508                                 only_whitespace = false;
509                                 break;
510                         }
511                 }
512                 if (only_whitespace) {
513                         do_base64 = true;
514                 }
515         }
516
517         if (!do_base64) {
518                 res = fprintf(add_fd, "%s: %s\n", attr_name, value);
519                 TALLOC_FREE(value);
520                 return res;
521         }
522
523         base64_blob.data = (unsigned char *)value;
524         base64_blob.length = strlen(value);
525
526         base64 = base64_encode_data_blob(value, base64_blob);
527         SMB_ASSERT(base64 != NULL);
528
529         res = fprintf(add_fd, "%s:: %s\n", attr_name, base64);
530         TALLOC_FREE(value);
531         return res;
532 }
533
534 /****************************************************************
535 ****************************************************************/
536
537 static NTSTATUS fetch_group_info_to_ldif(TALLOC_CTX *mem_ctx,
538                                          struct netr_DELTA_GROUP *r,
539                                          GROUPMAP *groupmap,
540                                          FILE *add_fd,
541                                          const char *sid,
542                                          const char *suffix)
543 {
544         const char *groupname = r->group_name.string;
545         uint32 grouptype = 0, g_rid = 0;
546         char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
547
548         /* Set up the group type (always 2 for group info) */
549         grouptype = 2;
550
551         /* These groups are entered by populate_ldap_for_ldif */
552         if (strcmp(groupname, "Domain Admins") == 0 ||
553             strcmp(groupname, "Domain Users") == 0 ||
554             strcmp(groupname, "Domain Guests") == 0 ||
555             strcmp(groupname, "Domain Computers") == 0 ||
556             strcmp(groupname, "Administrators") == 0 ||
557             strcmp(groupname, "Print Operators") == 0 ||
558             strcmp(groupname, "Backup Operators") == 0 ||
559             strcmp(groupname, "Replicators") == 0) {
560                 SAFE_FREE(group_attr);
561                 return NT_STATUS_OK;
562         } else {
563                 /* Increment the gid for the new group */
564                 ldif_gid++;
565         }
566
567         /* Map the group rid, gid, and dn */
568         g_rid = r->rid;
569         groupmap->rid = g_rid;
570         groupmap->gidNumber = ldif_gid;
571         groupmap->sambaSID      = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
572         groupmap->group_dn      = talloc_asprintf(mem_ctx,
573              "cn=%s,ou=%s,%s", groupname, group_attr, suffix);
574         if (groupmap->sambaSID == NULL || groupmap->group_dn == NULL) {
575                 SAFE_FREE(group_attr);
576                 return NT_STATUS_NO_MEMORY;
577         }
578
579         /* Write the data to the temporary add ldif file */
580         fprintf(add_fd, "# %s, %s, %s\n", groupname, group_attr,
581                 suffix);
582         fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", groupname, group_attr,
583                      suffix);
584         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
585         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
586         fprintf_attr(add_fd, "cn", "%s", groupname);
587         fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
588         fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
589         fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
590         fprintf_attr(add_fd, "displayName", "%s", groupname);
591         fprintf(add_fd, "\n");
592         fflush(add_fd);
593
594         SAFE_FREE(group_attr);
595         /* Return */
596         return NT_STATUS_OK;
597 }
598
599 /****************************************************************
600 ****************************************************************/
601
602 static NTSTATUS fetch_account_info_to_ldif(TALLOC_CTX *mem_ctx,
603                                            struct netr_DELTA_USER *r,
604                                            GROUPMAP *groupmap,
605                                            ACCOUNTMAP *accountmap,
606                                            FILE *add_fd,
607                                            const char *sid,
608                                            const char *suffix,
609                                            int alloced)
610 {
611         fstring username, logonscript, homedrive, homepath = "", homedir = "";
612         fstring hex_nt_passwd, hex_lm_passwd;
613         fstring description, profilepath, fullname, sambaSID;
614         char *flags, *user_rdn;
615         const char *ou;
616         const char* nopasswd = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
617         uchar zero_buf[16];
618         uint32 rid = 0, group_rid = 0, gidNumber = 0;
619         time_t unix_time;
620         int i, ret;
621
622         memset(zero_buf, '\0', sizeof(zero_buf));
623
624         /* Get the username */
625         fstrcpy(username, r->account_name.string);
626
627         /* Get the rid */
628         rid = r->rid;
629
630         /* Map the rid and username for group member info later */
631         accountmap->rid = rid;
632         accountmap->cn = talloc_strdup(mem_ctx, username);
633         NT_STATUS_HAVE_NO_MEMORY(accountmap->cn);
634
635         /* Get the home directory */
636         if (r->acct_flags & ACB_NORMAL) {
637                 fstrcpy(homedir, r->home_directory.string);
638                 if (!*homedir) {
639                         snprintf(homedir, sizeof(homedir), "/home/%s", username);
640                 } else {
641                         snprintf(homedir, sizeof(homedir), "/nobodyshomedir");
642                 }
643                 ou = lp_ldap_user_suffix();
644         } else {
645                 ou = lp_ldap_machine_suffix();
646                 snprintf(homedir, sizeof(homedir), "/machinehomedir");
647         }
648
649         /* Get the logon script */
650         fstrcpy(logonscript, r->logon_script.string);
651
652         /* Get the home drive */
653         fstrcpy(homedrive, r->home_drive.string);
654
655         /* Get the home path */
656         fstrcpy(homepath, r->home_directory.string);
657
658         /* Get the description */
659         fstrcpy(description, r->description.string);
660
661         /* Get the display name */
662         fstrcpy(fullname, r->full_name.string);
663
664         /* Get the profile path */
665         fstrcpy(profilepath, r->profile_path.string);
666
667         /* Get lm and nt password data */
668         if (memcmp(r->lmpassword.hash, zero_buf, 16) != 0) {
669                 pdb_sethexpwd(hex_lm_passwd, r->lmpassword.hash, r->acct_flags);
670         } else {
671                 pdb_sethexpwd(hex_lm_passwd, NULL, 0);
672         }
673         if (memcmp(r->ntpassword.hash, zero_buf, 16) != 0) {
674                 pdb_sethexpwd(hex_nt_passwd, r->ntpassword.hash, r->acct_flags);
675         } else {
676                 pdb_sethexpwd(hex_nt_passwd, NULL, 0);
677         }
678         unix_time = nt_time_to_unix(r->last_password_change);
679
680         /* Increment the uid for the new user */
681         ldif_uid++;
682
683         /* Set up group id and sambaSID for the user */
684         group_rid = r->primary_gid;
685         for (i=0; i<alloced; i++) {
686                 if (groupmap[i].rid == group_rid) break;
687         }
688         if (i == alloced){
689                 DEBUG(1, ("Could not find rid %d in groupmap array\n",
690                           group_rid));
691                 return NT_STATUS_UNSUCCESSFUL;
692         }
693         gidNumber = groupmap[i].gidNumber;
694         ret = snprintf(sambaSID, sizeof(sambaSID), "%s", groupmap[i].sambaSID);
695         if (ret < 0 || ret == sizeof(sambaSID)) {
696                 return NT_STATUS_UNSUCCESSFUL;
697         }
698
699         /* Set up sambaAcctFlags */
700         flags = pdb_encode_acct_ctrl(r->acct_flags,
701                                      NEW_PW_FORMAT_SPACE_PADDED_LEN);
702
703         /* Add the user to the temporary add ldif file */
704         /* this isn't quite right...we can't assume there's just OU=. jmcd */
705         user_rdn = sstring_sub(ou, '=', ',');
706         fprintf(add_fd, "# %s, %s, %s\n", username, user_rdn, suffix);
707         fprintf_attr(add_fd, "dn", "uid=%s,ou=%s,%s", username, user_rdn,
708                      suffix);
709         SAFE_FREE(user_rdn);
710         fprintf(add_fd, "ObjectClass: top\n");
711         fprintf(add_fd, "objectClass: inetOrgPerson\n");
712         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXACCOUNT);
713         fprintf(add_fd, "objectClass: shadowAccount\n");
714         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_SAMBASAMACCOUNT);
715         fprintf_attr(add_fd, "cn", "%s", username);
716         fprintf_attr(add_fd, "sn", "%s", username);
717         fprintf_attr(add_fd, "uid", "%s", username);
718         fprintf(add_fd, "uidNumber: %d\n", ldif_uid);
719         fprintf(add_fd, "gidNumber: %d\n", gidNumber);
720         fprintf_attr(add_fd, "homeDirectory", "%s", homedir);
721         if (*homepath)
722                 fprintf_attr(add_fd, "sambaHomePath", "%s", homepath);
723         if (*homedrive)
724                 fprintf_attr(add_fd, "sambaHomeDrive", "%s", homedrive);
725         if (*logonscript)
726                 fprintf_attr(add_fd, "sambaLogonScript", "%s", logonscript);
727         fprintf(add_fd, "loginShell: %s\n",
728                 ((r->acct_flags & ACB_NORMAL) ?
729                  "/bin/bash" : "/bin/false"));
730         fprintf(add_fd, "gecos: System User\n");
731         if (*description)
732                 fprintf_attr(add_fd, "description", "%s", description);
733         fprintf(add_fd, "sambaSID: %s-%d\n", sid, rid);
734         fprintf(add_fd, "sambaPrimaryGroupSID: %s\n", sambaSID);
735         if(*fullname)
736                 fprintf_attr(add_fd, "displayName", "%s", fullname);
737         if(*profilepath)
738                 fprintf_attr(add_fd, "sambaProfilePath", "%s", profilepath);
739         if (strcmp(nopasswd, hex_lm_passwd) != 0)
740                 fprintf(add_fd, "sambaLMPassword: %s\n", hex_lm_passwd);
741         if (strcmp(nopasswd, hex_nt_passwd) != 0)
742                 fprintf(add_fd, "sambaNTPassword: %s\n", hex_nt_passwd);
743         fprintf(add_fd, "sambaPwdLastSet: %d\n", (int)unix_time);
744         fprintf(add_fd, "sambaAcctFlags: %s\n", flags);
745         fprintf(add_fd, "\n");
746         fflush(add_fd);
747
748         /* Return */
749         return NT_STATUS_OK;
750 }
751
752 /****************************************************************
753 ****************************************************************/
754
755 static NTSTATUS fetch_alias_info_to_ldif(TALLOC_CTX *mem_ctx,
756                                          struct netr_DELTA_ALIAS *r,
757                                          GROUPMAP *groupmap,
758                                          FILE *add_fd,
759                                          const char *sid,
760                                          const char *suffix,
761                                          enum netr_SamDatabaseID database_id)
762 {
763         fstring aliasname, description;
764         uint32 grouptype = 0, g_rid = 0;
765         char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
766
767         /* Get the alias name */
768         fstrcpy(aliasname, r->alias_name.string);
769
770         /* Get the alias description */
771         fstrcpy(description, r->description.string);
772
773         /* Set up the group type */
774         switch (database_id) {
775         case SAM_DATABASE_DOMAIN:
776                 grouptype = 4;
777                 break;
778         case SAM_DATABASE_BUILTIN:
779                 grouptype = 5;
780                 break;
781         default:
782                 grouptype = 4;
783                 break;
784         }
785
786         /*
787           These groups are entered by populate_ldap_for_ldif
788           Note that populate creates a group called Relicators,
789           but NT returns a group called Replicator
790         */
791         if (strcmp(aliasname, "Domain Admins") == 0 ||
792             strcmp(aliasname, "Domain Users") == 0 ||
793             strcmp(aliasname, "Domain Guests") == 0 ||
794             strcmp(aliasname, "Domain Computers") == 0 ||
795             strcmp(aliasname, "Administrators") == 0 ||
796             strcmp(aliasname, "Print Operators") == 0 ||
797             strcmp(aliasname, "Backup Operators") == 0 ||
798             strcmp(aliasname, "Replicator") == 0) {
799                 SAFE_FREE(group_attr);
800                 return NT_STATUS_OK;
801         } else {
802                 /* Increment the gid for the new group */
803                 ldif_gid++;
804         }
805
806         /* Map the group rid and gid */
807         g_rid = r->rid;
808         groupmap->gidNumber = ldif_gid;
809         groupmap->sambaSID = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
810         if (groupmap->sambaSID == NULL) {
811                 SAFE_FREE(group_attr);
812                 return NT_STATUS_NO_MEMORY;
813         }
814
815         /* Write the data to the temporary add ldif file */
816         fprintf(add_fd, "# %s, %s, %s\n", aliasname, group_attr,
817                 suffix);
818         fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", aliasname, group_attr,
819                      suffix);
820         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
821         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
822         fprintf(add_fd, "cn: %s\n", aliasname);
823         fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
824         fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
825         fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
826         fprintf_attr(add_fd, "displayName", "%s", aliasname);
827         if (description[0])
828                 fprintf_attr(add_fd, "description", "%s", description);
829         fprintf(add_fd, "\n");
830         fflush(add_fd);
831
832         SAFE_FREE(group_attr);
833         /* Return */
834         return NT_STATUS_OK;
835 }
836
837 /****************************************************************
838 ****************************************************************/
839
840 static NTSTATUS fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER *r,
841                                             uint32_t id_rid,
842                                             GROUPMAP *groupmap,
843                                             ACCOUNTMAP *accountmap,
844                                             FILE *mod_fd, int alloced)
845 {
846         fstring group_dn;
847         uint32 group_rid = 0, rid = 0;
848         int i, j, k;
849
850         /* Get the dn for the group */
851         if (r->num_rids > 0) {
852                 group_rid = id_rid;
853                 for (j=0; j<alloced; j++) {
854                         if (groupmap[j].rid == group_rid) break;
855                 }
856                 if (j == alloced){
857                         DEBUG(1, ("Could not find rid %d in groupmap array\n",
858                                   group_rid));
859                         return NT_STATUS_UNSUCCESSFUL;
860                 }
861                 snprintf(group_dn, sizeof(group_dn), "%s", groupmap[j].group_dn);
862                 fprintf(mod_fd, "dn: %s\n", group_dn);
863
864                 /* Get the cn for each member */
865                 for (i=0; i < r->num_rids; i++) {
866                         rid = r->rids[i];
867                         for (k=0; k<alloced; k++) {
868                                 if (accountmap[k].rid == rid) break;
869                         }
870                         if (k == alloced){
871                                 DEBUG(1, ("Could not find rid %d in "
872                                           "accountmap array\n", rid));
873                                 return NT_STATUS_UNSUCCESSFUL;
874                         }
875                         fprintf(mod_fd, "memberUid: %s\n", accountmap[k].cn);
876                 }
877                 fprintf(mod_fd, "\n");
878         }
879         fflush(mod_fd);
880
881         /* Return */
882         return NT_STATUS_OK;
883 }
884
885 /****************************************************************
886 ****************************************************************/
887
888 static NTSTATUS ldif_init_context(TALLOC_CTX *mem_ctx,
889                                   enum netr_SamDatabaseID database_id,
890                                   const char *ldif_filename,
891                                   const char *domain_sid_str,
892                                   struct samsync_ldif_context **ctx)
893 {
894         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
895         struct samsync_ldif_context *r;
896         const char *add_template = "/tmp/add.ldif.XXXXXX";
897         const char *mod_template = "/tmp/mod.ldif.XXXXXX";
898         const char *builtin_sid = "S-1-5-32";
899
900         /* Get other smb.conf data */
901         if (!(lp_workgroup()) || !*(lp_workgroup())) {
902                 DEBUG(0,("workgroup missing from smb.conf--exiting\n"));
903                 exit(1);
904         }
905
906         /* Get the ldap suffix */
907         if (!(lp_ldap_suffix()) || !*(lp_ldap_suffix())) {
908                 DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
909                 exit(1);
910         }
911
912         if (*ctx && (*ctx)->initialized) {
913                 return NT_STATUS_OK;
914         }
915
916         r = TALLOC_ZERO_P(mem_ctx, struct samsync_ldif_context);
917         NT_STATUS_HAVE_NO_MEMORY(r);
918
919         /* Get the ldap suffix */
920         r->suffix = lp_ldap_suffix();
921
922         /* Ensure we have an output file */
923         if (ldif_filename) {
924                 r->ldif_file = fopen(ldif_filename, "a");
925         } else {
926                 r->ldif_file = stdout;
927         }
928
929         if (!r->ldif_file) {
930                 fprintf(stderr, "Could not open %s\n", ldif_filename);
931                 DEBUG(1, ("Could not open %s\n", ldif_filename));
932                 status = NT_STATUS_UNSUCCESSFUL;
933                 goto done;
934         }
935
936         r->add_template = talloc_strdup(mem_ctx, add_template);
937         r->mod_template = talloc_strdup(mem_ctx, mod_template);
938         if (!r->add_template || !r->mod_template) {
939                 status = NT_STATUS_NO_MEMORY;
940                 goto done;
941         }
942
943         r->add_name = talloc_strdup(mem_ctx, add_template);
944         r->module_name = talloc_strdup(mem_ctx, mod_template);
945         if (!r->add_name || !r->module_name) {
946                 status = NT_STATUS_NO_MEMORY;
947                 goto done;
948         }
949
950         /* Open the add and mod ldif files */
951         if (!(r->add_file = fdopen(mkstemp(r->add_name),"w"))) {
952                 DEBUG(1, ("Could not open %s\n", r->add_name));
953                 status = NT_STATUS_UNSUCCESSFUL;
954                 goto done;
955         }
956         if (!(r->mod_file = fdopen(mkstemp(r->module_name),"w"))) {
957                 DEBUG(1, ("Could not open %s\n", r->module_name));
958                 status = NT_STATUS_UNSUCCESSFUL;
959                 goto done;
960         }
961
962         /* Allocate initial memory for groupmap and accountmap arrays */
963         r->groupmap = TALLOC_ZERO_ARRAY(mem_ctx, GROUPMAP, 8);
964         r->accountmap = TALLOC_ZERO_ARRAY(mem_ctx, ACCOUNTMAP, 8);
965         if (r->groupmap == NULL || r->accountmap == NULL) {
966                 DEBUG(1,("GROUPMAP talloc failed\n"));
967                 status = NT_STATUS_NO_MEMORY;
968                 goto done;
969         }
970
971         /* Remember how many we malloced */
972         r->num_alloced = 8;
973
974         /* Initial database population */
975         if (database_id == SAM_DATABASE_DOMAIN) {
976
977                 status = populate_ldap_for_ldif(domain_sid_str,
978                                                 r->suffix,
979                                                 builtin_sid,
980                                                 r->add_file);
981                 if (!NT_STATUS_IS_OK(status)) {
982                         goto done;
983                 }
984
985                 status = map_populate_groups(mem_ctx,
986                                              r->groupmap,
987                                              r->accountmap,
988                                              domain_sid_str,
989                                              r->suffix,
990                                              builtin_sid);
991                 if (!NT_STATUS_IS_OK(status)) {
992                         goto done;
993                 }
994         }
995
996         r->initialized = true;
997
998         *ctx = r;
999
1000         return NT_STATUS_OK;
1001  done:
1002         TALLOC_FREE(r);
1003         return status;
1004 }
1005
1006 /****************************************************************
1007 ****************************************************************/
1008
1009 static void ldif_free_context(struct samsync_ldif_context *r)
1010 {
1011         if (!r) {
1012                 return;
1013         }
1014
1015         /* Close and delete the ldif files */
1016         if (r->add_file) {
1017                 fclose(r->add_file);
1018         }
1019
1020         if ((r->add_name != NULL) &&
1021             strcmp(r->add_name, r->add_template) && (unlink(r->add_name))) {
1022                 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
1023                          r->add_name, strerror(errno)));
1024         }
1025
1026         if (r->mod_file) {
1027                 fclose(r->mod_file);
1028         }
1029
1030         if ((r->module_name != NULL) &&
1031             strcmp(r->module_name, r->mod_template) && (unlink(r->module_name))) {
1032                 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
1033                          r->module_name, strerror(errno)));
1034         }
1035
1036         if (r->ldif_file && (r->ldif_file != stdout)) {
1037                 fclose(r->ldif_file);
1038         }
1039
1040         TALLOC_FREE(r);
1041 }
1042
1043 /****************************************************************
1044 ****************************************************************/
1045
1046 static void ldif_write_output(enum netr_SamDatabaseID database_id,
1047                               struct samsync_ldif_context *l)
1048 {
1049         /* Write ldif data to the user's file */
1050         if (database_id == SAM_DATABASE_DOMAIN) {
1051                 fprintf(l->ldif_file,
1052                         "# SAM_DATABASE_DOMAIN: ADD ENTITIES\n");
1053                 fprintf(l->ldif_file,
1054                         "# =================================\n\n");
1055                 fflush(l->ldif_file);
1056         } else if (database_id == SAM_DATABASE_BUILTIN) {
1057                 fprintf(l->ldif_file,
1058                         "# SAM_DATABASE_BUILTIN: ADD ENTITIES\n");
1059                 fprintf(l->ldif_file,
1060                         "# ==================================\n\n");
1061                 fflush(l->ldif_file);
1062         }
1063         fseek(l->add_file, 0, SEEK_SET);
1064         transfer_file(fileno(l->add_file), fileno(l->ldif_file), (size_t) -1);
1065
1066         if (database_id == SAM_DATABASE_DOMAIN) {
1067                 fprintf(l->ldif_file,
1068                         "# SAM_DATABASE_DOMAIN: MODIFY ENTITIES\n");
1069                 fprintf(l->ldif_file,
1070                         "# ====================================\n\n");
1071                 fflush(l->ldif_file);
1072         } else if (database_id == SAM_DATABASE_BUILTIN) {
1073                 fprintf(l->ldif_file,
1074                         "# SAM_DATABASE_BUILTIN: MODIFY ENTITIES\n");
1075                 fprintf(l->ldif_file,
1076                         "# =====================================\n\n");
1077                 fflush(l->ldif_file);
1078         }
1079         fseek(l->mod_file, 0, SEEK_SET);
1080         transfer_file(fileno(l->mod_file), fileno(l->ldif_file), (size_t) -1);
1081 }
1082
1083 /****************************************************************
1084 ****************************************************************/
1085
1086 static NTSTATUS fetch_sam_entry_ldif(TALLOC_CTX *mem_ctx,
1087                                      enum netr_SamDatabaseID database_id,
1088                                      struct netr_DELTA_ENUM *r,
1089                                      struct samsync_context *ctx,
1090                                      uint32_t *a_index_p,
1091                                      uint32_t *g_index_p)
1092 {
1093         union netr_DELTA_UNION u = r->delta_union;
1094         union netr_DELTA_ID_UNION id = r->delta_id_union;
1095         struct samsync_ldif_context *l =
1096                 talloc_get_type_abort(ctx->private_data, struct samsync_ldif_context);
1097
1098         switch (r->delta_type) {
1099                 case NETR_DELTA_DOMAIN:
1100                         break;
1101
1102                 case NETR_DELTA_GROUP:
1103                         fetch_group_info_to_ldif(mem_ctx,
1104                                                  u.group,
1105                                                  &l->groupmap[*g_index_p],
1106                                                  l->add_file,
1107                                                  ctx->domain_sid_str,
1108                                                  l->suffix);
1109                         (*g_index_p)++;
1110                         break;
1111
1112                 case NETR_DELTA_USER:
1113                         fetch_account_info_to_ldif(mem_ctx,
1114                                                    u.user,
1115                                                    l->groupmap,
1116                                                    &l->accountmap[*a_index_p],
1117                                                    l->add_file,
1118                                                    ctx->domain_sid_str,
1119                                                    l->suffix,
1120                                                    l->num_alloced);
1121                         (*a_index_p)++;
1122                         break;
1123
1124                 case NETR_DELTA_ALIAS:
1125                         fetch_alias_info_to_ldif(mem_ctx,
1126                                                  u.alias,
1127                                                  &l->groupmap[*g_index_p],
1128                                                  l->add_file,
1129                                                  ctx->domain_sid_str,
1130                                                  l->suffix,
1131                                                  database_id);
1132                         (*g_index_p)++;
1133                         break;
1134
1135                 case NETR_DELTA_GROUP_MEMBER:
1136                         fetch_groupmem_info_to_ldif(u.group_member,
1137                                                     id.rid,
1138                                                     l->groupmap,
1139                                                     l->accountmap,
1140                                                     l->mod_file,
1141                                                     l->num_alloced);
1142                         break;
1143
1144                 case NETR_DELTA_ALIAS_MEMBER:
1145                 case NETR_DELTA_POLICY:
1146                 case NETR_DELTA_ACCOUNT:
1147                 case NETR_DELTA_TRUSTED_DOMAIN:
1148                 case NETR_DELTA_SECRET:
1149                 case NETR_DELTA_RENAME_GROUP:
1150                 case NETR_DELTA_RENAME_USER:
1151                 case NETR_DELTA_RENAME_ALIAS:
1152                 case NETR_DELTA_DELETE_GROUP:
1153                 case NETR_DELTA_DELETE_USER:
1154                 case NETR_DELTA_MODIFY_COUNT:
1155                 default:
1156                         break;
1157         } /* end of switch */
1158
1159         return NT_STATUS_OK;
1160 }
1161
1162 /****************************************************************
1163 ****************************************************************/
1164
1165 static NTSTATUS ldif_realloc_maps(TALLOC_CTX *mem_ctx,
1166                                   struct samsync_ldif_context *l,
1167                                   uint32_t num_entries)
1168 {
1169         /* Re-allocate memory for groupmap and accountmap arrays */
1170         l->groupmap = TALLOC_REALLOC_ARRAY(mem_ctx,
1171                                            l->groupmap,
1172                                            GROUPMAP,
1173                                            num_entries + l->num_alloced);
1174
1175         l->accountmap = TALLOC_REALLOC_ARRAY(mem_ctx,
1176                                              l->accountmap,
1177                                              ACCOUNTMAP,
1178                                              num_entries + l->num_alloced);
1179
1180         if (l->groupmap == NULL || l->accountmap == NULL) {
1181                 DEBUG(1,("GROUPMAP talloc failed\n"));
1182                 return NT_STATUS_NO_MEMORY;
1183         }
1184
1185         /* Initialize the new records */
1186         memset(&(l->groupmap[l->num_alloced]), 0,
1187                sizeof(GROUPMAP) * num_entries);
1188         memset(&(l->accountmap[l->num_alloced]), 0,
1189                sizeof(ACCOUNTMAP) * num_entries);
1190
1191         /* Remember how many we alloced this time */
1192         l->num_alloced += num_entries;
1193
1194         return NT_STATUS_OK;
1195 }
1196
1197 /****************************************************************
1198 ****************************************************************/
1199
1200 static NTSTATUS init_ldif(TALLOC_CTX *mem_ctx,
1201                           struct samsync_context *ctx,
1202                           enum netr_SamDatabaseID database_id,
1203                           uint64_t *sequence_num)
1204 {
1205         NTSTATUS status;
1206         struct samsync_ldif_context *ldif_ctx =
1207                 (struct samsync_ldif_context *)ctx->private_data;
1208
1209         status = ldif_init_context(mem_ctx,
1210                                    database_id,
1211                                    ctx->output_filename,
1212                                    ctx->domain_sid_str,
1213                                    &ldif_ctx);
1214         if (!NT_STATUS_IS_OK(status)) {
1215                 return status;
1216         }
1217
1218         ctx->private_data = ldif_ctx;
1219
1220         return NT_STATUS_OK;
1221 }
1222
1223 /****************************************************************
1224 ****************************************************************/
1225
1226 static NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
1227                                        enum netr_SamDatabaseID database_id,
1228                                        struct netr_DELTA_ENUM_ARRAY *r,
1229                                        uint64_t *sequence_num,
1230                                        struct samsync_context *ctx)
1231 {
1232         NTSTATUS status;
1233         int i;
1234         struct samsync_ldif_context *ldif_ctx =
1235                 (struct samsync_ldif_context *)ctx->private_data;
1236
1237         status = ldif_realloc_maps(mem_ctx, ldif_ctx, r->num_deltas);
1238         if (!NT_STATUS_IS_OK(status)) {
1239                 goto failed;
1240         }
1241
1242         for (i = 0; i < r->num_deltas; i++) {
1243                 status = fetch_sam_entry_ldif(mem_ctx, database_id,
1244                                               &r->delta_enum[i], ctx,
1245                                               &a_index, &g_index);
1246                 if (!NT_STATUS_IS_OK(status)) {
1247                         goto failed;
1248                 }
1249         }
1250
1251         return NT_STATUS_OK;
1252
1253  failed:
1254         ldif_free_context(ldif_ctx);
1255         ctx->private_data = NULL;
1256
1257         return status;
1258 }
1259
1260 /****************************************************************
1261 ****************************************************************/
1262
1263 static NTSTATUS close_ldif(TALLOC_CTX *mem_ctx,
1264                            struct samsync_context *ctx,
1265                            enum netr_SamDatabaseID database_id,
1266                            uint64_t sequence_num)
1267 {
1268         struct samsync_ldif_context *ldif_ctx =
1269                 (struct samsync_ldif_context *)ctx->private_data;
1270
1271         /* This was the last query */
1272         ldif_write_output(database_id, ldif_ctx);
1273         if (ldif_ctx->ldif_file != stdout) {
1274                 ctx->result_message = talloc_asprintf(ctx,
1275                         "Vampired %d accounts and %d groups to %s",
1276                         a_index, g_index, ctx->output_filename);
1277         }
1278
1279         ldif_free_context(ldif_ctx);
1280         ctx->private_data = NULL;
1281
1282         return NT_STATUS_OK;
1283 }
1284
1285 #else /* HAVE_LDAP */
1286
1287 static NTSTATUS init_ldif(TALLOC_CTX *mem_ctx,
1288                           struct samsync_context *ctx,
1289                           enum netr_SamDatabaseID database_id,
1290                           uint64_t *sequence_num)
1291 {
1292         return NT_STATUS_NOT_SUPPORTED;
1293 }
1294
1295 static NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
1296                                        enum netr_SamDatabaseID database_id,
1297                                        struct netr_DELTA_ENUM_ARRAY *r,
1298                                        uint64_t *sequence_num,
1299                                        struct samsync_context *ctx)
1300 {
1301         return NT_STATUS_NOT_SUPPORTED;
1302 }
1303
1304 static NTSTATUS close_ldif(TALLOC_CTX *mem_ctx,
1305                            struct samsync_context *ctx,
1306                            enum netr_SamDatabaseID database_id,
1307                            uint64_t sequence_num)
1308 {
1309         return NT_STATUS_NOT_SUPPORTED;
1310 }
1311
1312 #endif
1313
1314 const struct samsync_ops libnet_samsync_ldif_ops = {
1315         .startup                = init_ldif,
1316         .process_objects        = fetch_sam_entries_ldif,
1317         .finish                 = close_ldif,
1318 };