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