werror: replace WERR_NO_SUCH_SERVICE with WERR_SERVICE_DOES_NOT_EXIST in source3...
[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, ...) PRINTF_ATTRIBUTE(3,4);
515
516 static int fprintf_attr(FILE *add_fd, const char *attr_name,
517                         const char *fmt, ...)
518 {
519         va_list ap;
520         char *value, *p, *base64;
521         DATA_BLOB base64_blob;
522         bool do_base64 = false;
523         int res;
524
525         va_start(ap, fmt);
526         value = talloc_vasprintf(NULL, fmt, ap);
527         va_end(ap);
528
529         SMB_ASSERT(value != NULL);
530
531         for (p=value; *p; p++) {
532                 if (*p & 0x80) {
533                         do_base64 = true;
534                         break;
535                 }
536         }
537
538         if (!do_base64) {
539                 bool only_whitespace = true;
540                 for (p=value; *p; p++) {
541                         /*
542                          * I know that this not multibyte safe, but we break
543                          * on the first non-whitespace character anyway.
544                          */
545                         if (!isspace(*p)) {
546                                 only_whitespace = false;
547                                 break;
548                         }
549                 }
550                 if (only_whitespace) {
551                         do_base64 = true;
552                 }
553         }
554
555         if (!do_base64) {
556                 res = fprintf(add_fd, "%s: %s\n", attr_name, value);
557                 TALLOC_FREE(value);
558                 return res;
559         }
560
561         base64_blob.data = (unsigned char *)value;
562         base64_blob.length = strlen(value);
563
564         base64 = base64_encode_data_blob(value, base64_blob);
565         SMB_ASSERT(base64 != NULL);
566
567         res = fprintf(add_fd, "%s:: %s\n", attr_name, base64);
568         TALLOC_FREE(value);
569         return res;
570 }
571
572 /****************************************************************
573 ****************************************************************/
574
575 static NTSTATUS fetch_group_info_to_ldif(TALLOC_CTX *mem_ctx,
576                                          struct netr_DELTA_GROUP *r,
577                                          GROUPMAP *groupmap,
578                                          FILE *add_fd,
579                                          const char *sid,
580                                          const char *suffix)
581 {
582         const char *groupname = r->group_name.string;
583         uint32_t grouptype = 0, g_rid = 0;
584         char *group_attr = sstring_sub(lp_ldap_group_suffix(talloc_tos()), '=', ',');
585
586         /* Set up the group type (always 2 for group info) */
587         grouptype = 2;
588
589         /* These groups are entered by populate_ldap_for_ldif */
590         if (strcmp(groupname, "Domain Admins") == 0 ||
591             strcmp(groupname, "Domain Users") == 0 ||
592             strcmp(groupname, "Domain Guests") == 0 ||
593             strcmp(groupname, "Domain Computers") == 0 ||
594             strcmp(groupname, "Administrators") == 0 ||
595             strcmp(groupname, "Print Operators") == 0 ||
596             strcmp(groupname, "Backup Operators") == 0 ||
597             strcmp(groupname, "Replicators") == 0) {
598                 SAFE_FREE(group_attr);
599                 return NT_STATUS_OK;
600         } else {
601                 /* Increment the gid for the new group */
602                 ldif_gid++;
603         }
604
605         /* Map the group rid, gid, and dn */
606         g_rid = r->rid;
607         groupmap->rid = g_rid;
608         groupmap->gidNumber = ldif_gid;
609         groupmap->sambaSID      = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
610         groupmap->group_dn      = talloc_asprintf(mem_ctx,
611              "cn=%s,ou=%s,%s", groupname, group_attr, suffix);
612         if (groupmap->sambaSID == NULL || groupmap->group_dn == NULL) {
613                 SAFE_FREE(group_attr);
614                 return NT_STATUS_NO_MEMORY;
615         }
616
617         /* Write the data to the temporary add ldif file */
618         fprintf(add_fd, "# %s, %s, %s\n", groupname, group_attr,
619                 suffix);
620         fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", groupname, group_attr,
621                      suffix);
622         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
623         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
624         fprintf_attr(add_fd, "cn", "%s", groupname);
625         fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
626         fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
627         fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
628         fprintf_attr(add_fd, "displayName", "%s", groupname);
629         fprintf(add_fd, "\n");
630         fflush(add_fd);
631
632         SAFE_FREE(group_attr);
633         /* Return */
634         return NT_STATUS_OK;
635 }
636
637 /****************************************************************
638 ****************************************************************/
639
640 static NTSTATUS fetch_account_info_to_ldif(TALLOC_CTX *mem_ctx,
641                                            struct netr_DELTA_USER *r,
642                                            GROUPMAP *groupmap,
643                                            ACCOUNTMAP *accountmap,
644                                            FILE *add_fd,
645                                            const char *sid,
646                                            const char *suffix,
647                                            int alloced)
648 {
649         fstring username, logonscript, homedrive, homepath = "", homedir = "";
650         fstring hex_nt_passwd, hex_lm_passwd;
651         fstring description, profilepath, fullname, sambaSID;
652         char *flags, *user_rdn;
653         const char *ou;
654         const char* nopasswd = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
655         uchar zero_buf[16];
656         uint32_t rid = 0, group_rid = 0, gidNumber = 0;
657         time_t unix_time;
658         int i, ret;
659
660         memset(zero_buf, '\0', sizeof(zero_buf));
661
662         /* Get the username */
663         fstrcpy(username, r->account_name.string);
664
665         /* Get the rid */
666         rid = r->rid;
667
668         /* Map the rid and username for group member info later */
669         accountmap->rid = rid;
670         accountmap->cn = talloc_strdup(mem_ctx, username);
671         NT_STATUS_HAVE_NO_MEMORY(accountmap->cn);
672
673         /* Get the home directory */
674         if (r->acct_flags & ACB_NORMAL) {
675                 fstrcpy(homedir, r->home_directory.string);
676                 if (!*homedir) {
677                         snprintf(homedir, sizeof(homedir), "/home/%s", username);
678                 } else {
679                         snprintf(homedir, sizeof(homedir), "/nobodyshomedir");
680                 }
681                 ou = lp_ldap_user_suffix(talloc_tos());
682         } else {
683                 ou = lp_ldap_machine_suffix(talloc_tos());
684                 snprintf(homedir, sizeof(homedir), "/machinehomedir");
685         }
686
687         /* Get the logon script */
688         fstrcpy(logonscript, r->logon_script.string);
689
690         /* Get the home drive */
691         fstrcpy(homedrive, r->home_drive.string);
692
693         /* Get the home path */
694         fstrcpy(homepath, r->home_directory.string);
695
696         /* Get the description */
697         fstrcpy(description, r->description.string);
698
699         /* Get the display name */
700         fstrcpy(fullname, r->full_name.string);
701
702         /* Get the profile path */
703         fstrcpy(profilepath, r->profile_path.string);
704
705         /* Get lm and nt password data */
706         if (memcmp(r->lmpassword.hash, zero_buf, 16) != 0) {
707                 pdb_sethexpwd(hex_lm_passwd, r->lmpassword.hash, r->acct_flags);
708         } else {
709                 pdb_sethexpwd(hex_lm_passwd, NULL, 0);
710         }
711         if (memcmp(r->ntpassword.hash, zero_buf, 16) != 0) {
712                 pdb_sethexpwd(hex_nt_passwd, r->ntpassword.hash, r->acct_flags);
713         } else {
714                 pdb_sethexpwd(hex_nt_passwd, NULL, 0);
715         }
716         unix_time = nt_time_to_unix(r->last_password_change);
717
718         /* Increment the uid for the new user */
719         ldif_uid++;
720
721         /* Set up group id and sambaSID for the user */
722         group_rid = r->primary_gid;
723         for (i=0; i<alloced; i++) {
724                 if (groupmap[i].rid == group_rid) break;
725         }
726         if (i == alloced){
727                 DEBUG(1, ("Could not find rid %d in groupmap array\n",
728                           group_rid));
729                 return NT_STATUS_UNSUCCESSFUL;
730         }
731         gidNumber = groupmap[i].gidNumber;
732         ret = snprintf(sambaSID, sizeof(sambaSID), "%s", groupmap[i].sambaSID);
733         if (ret < 0 || ret == sizeof(sambaSID)) {
734                 return NT_STATUS_UNSUCCESSFUL;
735         }
736
737         /* Set up sambaAcctFlags */
738         flags = pdb_encode_acct_ctrl(r->acct_flags,
739                                      NEW_PW_FORMAT_SPACE_PADDED_LEN);
740
741         /* Add the user to the temporary add ldif file */
742         /* this isn't quite right...we can't assume there's just OU=. jmcd */
743         user_rdn = sstring_sub(ou, '=', ',');
744         fprintf(add_fd, "# %s, %s, %s\n", username, user_rdn, suffix);
745         fprintf_attr(add_fd, "dn", "uid=%s,ou=%s,%s", username, user_rdn,
746                      suffix);
747         SAFE_FREE(user_rdn);
748         fprintf(add_fd, "ObjectClass: top\n");
749         fprintf(add_fd, "objectClass: inetOrgPerson\n");
750         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXACCOUNT);
751         fprintf(add_fd, "objectClass: shadowAccount\n");
752         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_SAMBASAMACCOUNT);
753         fprintf_attr(add_fd, "cn", "%s", username);
754         fprintf_attr(add_fd, "sn", "%s", username);
755         fprintf_attr(add_fd, "uid", "%s", username);
756         fprintf(add_fd, "uidNumber: %d\n", ldif_uid);
757         fprintf(add_fd, "gidNumber: %d\n", gidNumber);
758         fprintf_attr(add_fd, "homeDirectory", "%s", homedir);
759         if (*homepath)
760                 fprintf_attr(add_fd, "sambaHomePath", "%s", homepath);
761         if (*homedrive)
762                 fprintf_attr(add_fd, "sambaHomeDrive", "%s", homedrive);
763         if (*logonscript)
764                 fprintf_attr(add_fd, "sambaLogonScript", "%s", logonscript);
765         fprintf(add_fd, "loginShell: %s\n",
766                 ((r->acct_flags & ACB_NORMAL) ?
767                  "/bin/bash" : "/bin/false"));
768         fprintf(add_fd, "gecos: System User\n");
769         if (*description)
770                 fprintf_attr(add_fd, "description", "%s", description);
771         fprintf(add_fd, "sambaSID: %s-%d\n", sid, rid);
772         fprintf(add_fd, "sambaPrimaryGroupSID: %s\n", sambaSID);
773         if(*fullname)
774                 fprintf_attr(add_fd, "displayName", "%s", fullname);
775         if(*profilepath)
776                 fprintf_attr(add_fd, "sambaProfilePath", "%s", profilepath);
777         if (strcmp(nopasswd, hex_lm_passwd) != 0)
778                 fprintf(add_fd, "sambaLMPassword: %s\n", hex_lm_passwd);
779         if (strcmp(nopasswd, hex_nt_passwd) != 0)
780                 fprintf(add_fd, "sambaNTPassword: %s\n", hex_nt_passwd);
781         fprintf(add_fd, "sambaPwdLastSet: %d\n", (int)unix_time);
782         fprintf(add_fd, "sambaAcctFlags: %s\n", flags);
783         fprintf(add_fd, "\n");
784         fflush(add_fd);
785
786         /* Return */
787         return NT_STATUS_OK;
788 }
789
790 /****************************************************************
791 ****************************************************************/
792
793 static NTSTATUS fetch_alias_info_to_ldif(TALLOC_CTX *mem_ctx,
794                                          struct netr_DELTA_ALIAS *r,
795                                          GROUPMAP *groupmap,
796                                          FILE *add_fd,
797                                          const char *sid,
798                                          const char *suffix,
799                                          enum netr_SamDatabaseID database_id)
800 {
801         fstring aliasname, description;
802         uint32_t grouptype = 0, g_rid = 0;
803         char *group_attr = sstring_sub(lp_ldap_group_suffix(talloc_tos()), '=', ',');
804
805         /* Get the alias name */
806         fstrcpy(aliasname, r->alias_name.string);
807
808         /* Get the alias description */
809         fstrcpy(description, r->description.string);
810
811         /* Set up the group type */
812         switch (database_id) {
813         case SAM_DATABASE_DOMAIN:
814                 grouptype = 4;
815                 break;
816         case SAM_DATABASE_BUILTIN:
817                 grouptype = 5;
818                 break;
819         default:
820                 grouptype = 4;
821                 break;
822         }
823
824         /*
825           These groups are entered by populate_ldap_for_ldif
826           Note that populate creates a group called Relicators,
827           but NT returns a group called Replicator
828         */
829         if (strcmp(aliasname, "Domain Admins") == 0 ||
830             strcmp(aliasname, "Domain Users") == 0 ||
831             strcmp(aliasname, "Domain Guests") == 0 ||
832             strcmp(aliasname, "Domain Computers") == 0 ||
833             strcmp(aliasname, "Administrators") == 0 ||
834             strcmp(aliasname, "Print Operators") == 0 ||
835             strcmp(aliasname, "Backup Operators") == 0 ||
836             strcmp(aliasname, "Replicator") == 0) {
837                 SAFE_FREE(group_attr);
838                 return NT_STATUS_OK;
839         } else {
840                 /* Increment the gid for the new group */
841                 ldif_gid++;
842         }
843
844         /* Map the group rid and gid */
845         g_rid = r->rid;
846         groupmap->gidNumber = ldif_gid;
847         groupmap->sambaSID = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
848         if (groupmap->sambaSID == NULL) {
849                 SAFE_FREE(group_attr);
850                 return NT_STATUS_NO_MEMORY;
851         }
852
853         /* Write the data to the temporary add ldif file */
854         fprintf(add_fd, "# %s, %s, %s\n", aliasname, group_attr,
855                 suffix);
856         fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", aliasname, group_attr,
857                      suffix);
858         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
859         fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
860         fprintf(add_fd, "cn: %s\n", aliasname);
861         fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
862         fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
863         fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
864         fprintf_attr(add_fd, "displayName", "%s", aliasname);
865         if (description[0])
866                 fprintf_attr(add_fd, "description", "%s", description);
867         fprintf(add_fd, "\n");
868         fflush(add_fd);
869
870         SAFE_FREE(group_attr);
871         /* Return */
872         return NT_STATUS_OK;
873 }
874
875 /****************************************************************
876 ****************************************************************/
877
878 static NTSTATUS fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER *r,
879                                             uint32_t id_rid,
880                                             GROUPMAP *groupmap,
881                                             ACCOUNTMAP *accountmap,
882                                             FILE *mod_fd, int alloced)
883 {
884         fstring group_dn;
885         uint32_t group_rid = 0, rid = 0;
886         int i, j, k;
887
888         /* Get the dn for the group */
889         if (r->num_rids > 0) {
890                 group_rid = id_rid;
891                 for (j=0; j<alloced; j++) {
892                         if (groupmap[j].rid == group_rid) break;
893                 }
894                 if (j == alloced){
895                         DEBUG(1, ("Could not find rid %d in groupmap array\n",
896                                   group_rid));
897                         return NT_STATUS_UNSUCCESSFUL;
898                 }
899                 snprintf(group_dn, sizeof(group_dn), "%s", groupmap[j].group_dn);
900                 fprintf(mod_fd, "dn: %s\n", group_dn);
901
902                 /* Get the cn for each member */
903                 for (i=0; i < r->num_rids; i++) {
904                         rid = r->rids[i];
905                         for (k=0; k<alloced; k++) {
906                                 if (accountmap[k].rid == rid) break;
907                         }
908                         if (k == alloced){
909                                 DEBUG(1, ("Could not find rid %d in "
910                                           "accountmap array\n", rid));
911                                 return NT_STATUS_UNSUCCESSFUL;
912                         }
913                         fprintf(mod_fd, "memberUid: %s\n", accountmap[k].cn);
914                 }
915                 fprintf(mod_fd, "\n");
916         }
917         fflush(mod_fd);
918
919         /* Return */
920         return NT_STATUS_OK;
921 }
922
923 /****************************************************************
924 ****************************************************************/
925
926 static NTSTATUS ldif_init_context(TALLOC_CTX *mem_ctx,
927                                   enum netr_SamDatabaseID database_id,
928                                   const char *ldif_filename,
929                                   const char *domain_sid_str,
930                                   struct samsync_ldif_context **ctx)
931 {
932         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
933         struct samsync_ldif_context *r;
934         const char *add_template = "/tmp/add.ldif.XXXXXX";
935         const char *mod_template = "/tmp/mod.ldif.XXXXXX";
936         const char *builtin_sid = "S-1-5-32";
937         mode_t mask;
938         int fd;
939
940         r = talloc_zero(mem_ctx, struct samsync_ldif_context);
941         NT_STATUS_HAVE_NO_MEMORY(r);
942
943         /* Get the ldap suffix */
944         r->suffix = lp_ldap_suffix(talloc_tos());
945
946         /* Get other smb.conf data */
947         if (!(lp_workgroup()) || !*(lp_workgroup())) {
948                 DEBUG(0,("workgroup missing from smb.conf--exiting\n"));
949                 exit(1);
950         }
951
952         /* Get the ldap suffix */
953         if (!r->suffix || !*r->suffix) {
954                 DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
955                 exit(1);
956         }
957
958         if (*ctx && (*ctx)->initialized) {
959                 return NT_STATUS_OK;
960         }
961
962         /* Ensure we have an output file */
963         if (ldif_filename) {
964                 r->ldif_file = fopen(ldif_filename, "a");
965         } else {
966                 r->ldif_file = stdout;
967         }
968
969         if (!r->ldif_file) {
970                 fprintf(stderr, "Could not open %s\n", ldif_filename);
971                 DEBUG(1, ("Could not open %s\n", ldif_filename));
972                 status = NT_STATUS_UNSUCCESSFUL;
973                 goto done;
974         }
975
976         r->add_template = talloc_strdup(mem_ctx, add_template);
977         r->mod_template = talloc_strdup(mem_ctx, mod_template);
978         if (!r->add_template || !r->mod_template) {
979                 status = NT_STATUS_NO_MEMORY;
980                 goto done;
981         }
982
983         r->add_name = talloc_strdup(mem_ctx, add_template);
984         r->module_name = talloc_strdup(mem_ctx, mod_template);
985         if (!r->add_name || !r->module_name) {
986                 status = NT_STATUS_NO_MEMORY;
987                 goto done;
988         }
989
990         mask = umask(S_IRWXO | S_IRWXG);
991         fd = mkstemp(r->add_name);
992         umask(mask);
993         if (fd < 0) {
994                 DEBUG(1, ("Could not create %s\n", r->add_name));
995                 status = NT_STATUS_UNSUCCESSFUL;
996                 goto done;
997         }
998
999         /* Open the add and mod ldif files */
1000         r->add_file = fdopen(fd, "w");
1001         if (r->add_file == NULL) {
1002                 DEBUG(1, ("Could not open %s\n", r->add_name));
1003                 close(fd);
1004                 status = NT_STATUS_UNSUCCESSFUL;
1005                 goto done;
1006         }
1007
1008         mask = umask(S_IRWXO | S_IRWXG);
1009         fd = mkstemp(r->module_name);
1010         umask(mask);
1011         if (fd < 0) {
1012                 DEBUG(1, ("Could not create %s\n", r->module_name));
1013                 status = NT_STATUS_UNSUCCESSFUL;
1014                 goto done;
1015         }
1016
1017         r->mod_file = fdopen(fd, "w");
1018         if (r->mod_file == NULL) {
1019                 DEBUG(1, ("Could not open %s\n", r->module_name));
1020                 close(fd);
1021                 status = NT_STATUS_UNSUCCESSFUL;
1022                 goto done;
1023         }
1024
1025         /* Allocate initial memory for groupmap and accountmap arrays */
1026         r->groupmap = talloc_zero_array(mem_ctx, GROUPMAP, 8);
1027         r->accountmap = talloc_zero_array(mem_ctx, ACCOUNTMAP, 8);
1028         if (r->groupmap == NULL || r->accountmap == NULL) {
1029                 DEBUG(1,("GROUPMAP talloc failed\n"));
1030                 status = NT_STATUS_NO_MEMORY;
1031                 goto done;
1032         }
1033
1034         /* Remember how many we malloced */
1035         r->num_alloced = 8;
1036
1037         /* Initial database population */
1038         if (database_id == SAM_DATABASE_DOMAIN) {
1039
1040                 status = populate_ldap_for_ldif(domain_sid_str,
1041                                                 r->suffix,
1042                                                 builtin_sid,
1043                                                 r->add_file);
1044                 if (!NT_STATUS_IS_OK(status)) {
1045                         goto done;
1046                 }
1047
1048                 status = map_populate_groups(mem_ctx,
1049                                              r->groupmap,
1050                                              r->accountmap,
1051                                              domain_sid_str,
1052                                              r->suffix,
1053                                              builtin_sid);
1054                 if (!NT_STATUS_IS_OK(status)) {
1055                         goto done;
1056                 }
1057         }
1058
1059         r->initialized = true;
1060
1061         *ctx = r;
1062
1063         return NT_STATUS_OK;
1064  done:
1065         TALLOC_FREE(r);
1066         return status;
1067 }
1068
1069 /****************************************************************
1070 ****************************************************************/
1071
1072 static void ldif_free_context(struct samsync_ldif_context *r)
1073 {
1074         if (!r) {
1075                 return;
1076         }
1077
1078         /* Close and delete the ldif files */
1079         if (r->add_file) {
1080                 fclose(r->add_file);
1081         }
1082
1083         if ((r->add_name != NULL) &&
1084             strcmp(r->add_name, r->add_template) && (unlink(r->add_name))) {
1085                 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
1086                          r->add_name, strerror(errno)));
1087         }
1088
1089         if (r->mod_file) {
1090                 fclose(r->mod_file);
1091         }
1092
1093         if ((r->module_name != NULL) &&
1094             strcmp(r->module_name, r->mod_template) && (unlink(r->module_name))) {
1095                 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
1096                          r->module_name, strerror(errno)));
1097         }
1098
1099         if (r->ldif_file && (r->ldif_file != stdout)) {
1100                 fclose(r->ldif_file);
1101         }
1102
1103         TALLOC_FREE(r);
1104 }
1105
1106 /****************************************************************
1107 ****************************************************************/
1108
1109 static void ldif_write_output(enum netr_SamDatabaseID database_id,
1110                               struct samsync_ldif_context *l)
1111 {
1112         /* Write ldif data to the user's file */
1113         if (database_id == SAM_DATABASE_DOMAIN) {
1114                 fprintf(l->ldif_file,
1115                         "# SAM_DATABASE_DOMAIN: ADD ENTITIES\n");
1116                 fprintf(l->ldif_file,
1117                         "# =================================\n\n");
1118                 fflush(l->ldif_file);
1119         } else if (database_id == SAM_DATABASE_BUILTIN) {
1120                 fprintf(l->ldif_file,
1121                         "# SAM_DATABASE_BUILTIN: ADD ENTITIES\n");
1122                 fprintf(l->ldif_file,
1123                         "# ==================================\n\n");
1124                 fflush(l->ldif_file);
1125         }
1126         fseek(l->add_file, 0, SEEK_SET);
1127         transfer_file(fileno(l->add_file), fileno(l->ldif_file), (size_t) -1);
1128
1129         if (database_id == SAM_DATABASE_DOMAIN) {
1130                 fprintf(l->ldif_file,
1131                         "# SAM_DATABASE_DOMAIN: MODIFY ENTITIES\n");
1132                 fprintf(l->ldif_file,
1133                         "# ====================================\n\n");
1134                 fflush(l->ldif_file);
1135         } else if (database_id == SAM_DATABASE_BUILTIN) {
1136                 fprintf(l->ldif_file,
1137                         "# SAM_DATABASE_BUILTIN: MODIFY ENTITIES\n");
1138                 fprintf(l->ldif_file,
1139                         "# =====================================\n\n");
1140                 fflush(l->ldif_file);
1141         }
1142         fseek(l->mod_file, 0, SEEK_SET);
1143         transfer_file(fileno(l->mod_file), fileno(l->ldif_file), (size_t) -1);
1144 }
1145
1146 /****************************************************************
1147 ****************************************************************/
1148
1149 static NTSTATUS fetch_sam_entry_ldif(TALLOC_CTX *mem_ctx,
1150                                      enum netr_SamDatabaseID database_id,
1151                                      struct netr_DELTA_ENUM *r,
1152                                      struct samsync_context *ctx,
1153                                      uint32_t *a_index_p,
1154                                      uint32_t *g_index_p)
1155 {
1156         union netr_DELTA_UNION u = r->delta_union;
1157         union netr_DELTA_ID_UNION id = r->delta_id_union;
1158         struct samsync_ldif_context *l =
1159                 talloc_get_type_abort(ctx->private_data, struct samsync_ldif_context);
1160
1161         switch (r->delta_type) {
1162                 case NETR_DELTA_DOMAIN:
1163                         break;
1164
1165                 case NETR_DELTA_GROUP:
1166                         fetch_group_info_to_ldif(mem_ctx,
1167                                                  u.group,
1168                                                  &l->groupmap[*g_index_p],
1169                                                  l->add_file,
1170                                                  ctx->domain_sid_str,
1171                                                  l->suffix);
1172                         (*g_index_p)++;
1173                         break;
1174
1175                 case NETR_DELTA_USER:
1176                         fetch_account_info_to_ldif(mem_ctx,
1177                                                    u.user,
1178                                                    l->groupmap,
1179                                                    &l->accountmap[*a_index_p],
1180                                                    l->add_file,
1181                                                    ctx->domain_sid_str,
1182                                                    l->suffix,
1183                                                    l->num_alloced);
1184                         (*a_index_p)++;
1185                         break;
1186
1187                 case NETR_DELTA_ALIAS:
1188                         fetch_alias_info_to_ldif(mem_ctx,
1189                                                  u.alias,
1190                                                  &l->groupmap[*g_index_p],
1191                                                  l->add_file,
1192                                                  ctx->domain_sid_str,
1193                                                  l->suffix,
1194                                                  database_id);
1195                         (*g_index_p)++;
1196                         break;
1197
1198                 case NETR_DELTA_GROUP_MEMBER:
1199                         fetch_groupmem_info_to_ldif(u.group_member,
1200                                                     id.rid,
1201                                                     l->groupmap,
1202                                                     l->accountmap,
1203                                                     l->mod_file,
1204                                                     l->num_alloced);
1205                         break;
1206
1207                 case NETR_DELTA_ALIAS_MEMBER:
1208                 case NETR_DELTA_POLICY:
1209                 case NETR_DELTA_ACCOUNT:
1210                 case NETR_DELTA_TRUSTED_DOMAIN:
1211                 case NETR_DELTA_SECRET:
1212                 case NETR_DELTA_RENAME_GROUP:
1213                 case NETR_DELTA_RENAME_USER:
1214                 case NETR_DELTA_RENAME_ALIAS:
1215                 case NETR_DELTA_DELETE_GROUP:
1216                 case NETR_DELTA_DELETE_USER:
1217                 case NETR_DELTA_MODIFY_COUNT:
1218                 default:
1219                         break;
1220         } /* end of switch */
1221
1222         return NT_STATUS_OK;
1223 }
1224
1225 /****************************************************************
1226 ****************************************************************/
1227
1228 static NTSTATUS ldif_realloc_maps(TALLOC_CTX *mem_ctx,
1229                                   struct samsync_ldif_context *l,
1230                                   uint32_t num_entries)
1231 {
1232         /* Re-allocate memory for groupmap and accountmap arrays */
1233         l->groupmap = talloc_realloc(mem_ctx,
1234                                            l->groupmap,
1235                                            GROUPMAP,
1236                                            num_entries + l->num_alloced);
1237
1238         l->accountmap = talloc_realloc(mem_ctx,
1239                                              l->accountmap,
1240                                              ACCOUNTMAP,
1241                                              num_entries + l->num_alloced);
1242
1243         if (l->groupmap == NULL || l->accountmap == NULL) {
1244                 DEBUG(1,("GROUPMAP talloc failed\n"));
1245                 return NT_STATUS_NO_MEMORY;
1246         }
1247
1248         /* Initialize the new records */
1249         memset(&(l->groupmap[l->num_alloced]), 0,
1250                sizeof(GROUPMAP) * num_entries);
1251         memset(&(l->accountmap[l->num_alloced]), 0,
1252                sizeof(ACCOUNTMAP) * num_entries);
1253
1254         /* Remember how many we alloced this time */
1255         l->num_alloced += num_entries;
1256
1257         return NT_STATUS_OK;
1258 }
1259
1260 /****************************************************************
1261 ****************************************************************/
1262
1263 static NTSTATUS init_ldif(TALLOC_CTX *mem_ctx,
1264                           struct samsync_context *ctx,
1265                           enum netr_SamDatabaseID database_id,
1266                           uint64_t *sequence_num)
1267 {
1268         NTSTATUS status;
1269         struct samsync_ldif_context *ldif_ctx =
1270                 (struct samsync_ldif_context *)ctx->private_data;
1271
1272         status = ldif_init_context(mem_ctx,
1273                                    database_id,
1274                                    ctx->output_filename,
1275                                    ctx->domain_sid_str,
1276                                    &ldif_ctx);
1277         if (!NT_STATUS_IS_OK(status)) {
1278                 return status;
1279         }
1280
1281         ctx->private_data = ldif_ctx;
1282
1283         return NT_STATUS_OK;
1284 }
1285
1286 /****************************************************************
1287 ****************************************************************/
1288
1289 static NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
1290                                        enum netr_SamDatabaseID database_id,
1291                                        struct netr_DELTA_ENUM_ARRAY *r,
1292                                        uint64_t *sequence_num,
1293                                        struct samsync_context *ctx)
1294 {
1295         NTSTATUS status;
1296         int i;
1297         struct samsync_ldif_context *ldif_ctx =
1298                 (struct samsync_ldif_context *)ctx->private_data;
1299
1300         status = ldif_realloc_maps(mem_ctx, ldif_ctx, r->num_deltas);
1301         if (!NT_STATUS_IS_OK(status)) {
1302                 goto failed;
1303         }
1304
1305         for (i = 0; i < r->num_deltas; i++) {
1306                 status = fetch_sam_entry_ldif(mem_ctx, database_id,
1307                                               &r->delta_enum[i], ctx,
1308                                               &a_index, &g_index);
1309                 if (!NT_STATUS_IS_OK(status)) {
1310                         goto failed;
1311                 }
1312         }
1313
1314         return NT_STATUS_OK;
1315
1316  failed:
1317         ldif_free_context(ldif_ctx);
1318         ctx->private_data = NULL;
1319
1320         return status;
1321 }
1322
1323 /****************************************************************
1324 ****************************************************************/
1325
1326 static NTSTATUS close_ldif(TALLOC_CTX *mem_ctx,
1327                            struct samsync_context *ctx,
1328                            enum netr_SamDatabaseID database_id,
1329                            uint64_t sequence_num)
1330 {
1331         struct samsync_ldif_context *ldif_ctx =
1332                 (struct samsync_ldif_context *)ctx->private_data;
1333
1334         /* This was the last query */
1335         ldif_write_output(database_id, ldif_ctx);
1336         if (ldif_ctx->ldif_file != stdout) {
1337                 ctx->result_message = talloc_asprintf(ctx,
1338                         "Vampired %d accounts and %d groups to %s",
1339                         a_index, g_index, ctx->output_filename);
1340         }
1341
1342         ldif_free_context(ldif_ctx);
1343         ctx->private_data = NULL;
1344
1345         return NT_STATUS_OK;
1346 }
1347
1348 #else /* HAVE_LDAP */
1349
1350 static NTSTATUS init_ldif(TALLOC_CTX *mem_ctx,
1351                           struct samsync_context *ctx,
1352                           enum netr_SamDatabaseID database_id,
1353                           uint64_t *sequence_num)
1354 {
1355         return NT_STATUS_NOT_SUPPORTED;
1356 }
1357
1358 static NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
1359                                        enum netr_SamDatabaseID database_id,
1360                                        struct netr_DELTA_ENUM_ARRAY *r,
1361                                        uint64_t *sequence_num,
1362                                        struct samsync_context *ctx)
1363 {
1364         return NT_STATUS_NOT_SUPPORTED;
1365 }
1366
1367 static NTSTATUS close_ldif(TALLOC_CTX *mem_ctx,
1368                            struct samsync_context *ctx,
1369                            enum netr_SamDatabaseID database_id,
1370                            uint64_t sequence_num)
1371 {
1372         return NT_STATUS_NOT_SUPPORTED;
1373 }
1374
1375 #endif
1376
1377 const struct samsync_ops libnet_samsync_ldif_ops = {
1378         .startup                = init_ldif,
1379         .process_objects        = fetch_sam_entries_ldif,
1380         .finish                 = close_ldif,
1381 };