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