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