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