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