smbldap: Fix typo in debug message.
[Samba.git] / source / libnet / libnet_samsync_ldif.c
blobc89fedc2a3582f77d2aa6ea25714e1b02bf133e6
1 /*
2 Unix SMB/CIFS implementation.
3 dump the remote SAM using rpc samsync operations
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.
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.
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.
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/>.
26 #include "includes.h"
27 #include "libnet/libnet_samsync.h"
29 /* uid's and gid's for writing deltas to ldif */
30 static uint32 ldif_gid = 999;
31 static uint32 ldif_uid = 999;
33 /* Structure for mapping accounts to groups */
34 /* Array element is the group rid */
35 typedef struct _groupmap {
36 uint32_t rid;
37 uint32_t gidNumber;
38 const char *sambaSID;
39 const char *group_dn;
40 } GROUPMAP;
42 typedef struct _accountmap {
43 uint32_t rid;
44 const char *cn;
45 } ACCOUNTMAP;
47 struct samsync_ldif_context {
48 GROUPMAP *groupmap;
49 ACCOUNTMAP *accountmap;
50 bool initialized;
51 const char *add_template;
52 const char *mod_template;
53 char *add_name;
54 char *mod_name;
55 FILE *add_file;
56 FILE *mod_file;
57 FILE *ldif_file;
58 const char *suffix;
59 int num_alloced;
62 /****************************************************************
63 ****************************************************************/
65 static NTSTATUS populate_ldap_for_ldif(const char *sid,
66 const char *suffix,
67 const char *builtin_sid,
68 FILE *add_fd)
70 const char *user_suffix, *group_suffix, *machine_suffix, *idmap_suffix;
71 char *user_attr=NULL, *group_attr=NULL;
72 char *suffix_attr;
73 int len;
75 /* Get the suffix attribute */
76 suffix_attr = sstring_sub(suffix, '=', ',');
77 if (suffix_attr == NULL) {
78 len = strlen(suffix);
79 suffix_attr = (char*)SMB_MALLOC(len+1);
80 memcpy(suffix_attr, suffix, len);
81 suffix_attr[len] = '\0';
84 /* Write the base */
85 fprintf(add_fd, "# %s\n", suffix);
86 fprintf(add_fd, "dn: %s\n", suffix);
87 fprintf(add_fd, "objectClass: dcObject\n");
88 fprintf(add_fd, "objectClass: organization\n");
89 fprintf(add_fd, "o: %s\n", suffix_attr);
90 fprintf(add_fd, "dc: %s\n", suffix_attr);
91 fprintf(add_fd, "\n");
92 fflush(add_fd);
94 user_suffix = lp_ldap_user_suffix();
95 if (user_suffix == NULL) {
96 SAFE_FREE(suffix_attr);
97 return NT_STATUS_NO_MEMORY;
99 /* If it exists and is distinct from other containers,
100 Write the Users entity */
101 if (*user_suffix && strcmp(user_suffix, suffix)) {
102 user_attr = sstring_sub(lp_ldap_user_suffix(), '=', ',');
103 fprintf(add_fd, "# %s\n", user_suffix);
104 fprintf(add_fd, "dn: %s\n", user_suffix);
105 fprintf(add_fd, "objectClass: organizationalUnit\n");
106 fprintf(add_fd, "ou: %s\n", user_attr);
107 fprintf(add_fd, "\n");
108 fflush(add_fd);
112 group_suffix = lp_ldap_group_suffix();
113 if (group_suffix == NULL) {
114 SAFE_FREE(suffix_attr);
115 SAFE_FREE(user_attr);
116 return NT_STATUS_NO_MEMORY;
118 /* If it exists and is distinct from other containers,
119 Write the Groups entity */
120 if (*group_suffix && strcmp(group_suffix, suffix)) {
121 group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
122 fprintf(add_fd, "# %s\n", group_suffix);
123 fprintf(add_fd, "dn: %s\n", group_suffix);
124 fprintf(add_fd, "objectClass: organizationalUnit\n");
125 fprintf(add_fd, "ou: %s\n", group_attr);
126 fprintf(add_fd, "\n");
127 fflush(add_fd);
130 /* If it exists and is distinct from other containers,
131 Write the Computers entity */
132 machine_suffix = lp_ldap_machine_suffix();
133 if (machine_suffix == NULL) {
134 SAFE_FREE(suffix_attr);
135 SAFE_FREE(user_attr);
136 SAFE_FREE(group_attr);
137 return NT_STATUS_NO_MEMORY;
139 if (*machine_suffix && strcmp(machine_suffix, user_suffix) &&
140 strcmp(machine_suffix, suffix)) {
141 char *machine_ou = NULL;
142 fprintf(add_fd, "# %s\n", machine_suffix);
143 fprintf(add_fd, "dn: %s\n", machine_suffix);
144 fprintf(add_fd, "objectClass: organizationalUnit\n");
145 /* this isn't totally correct as it assumes that
146 there _must_ be an ou. just fixing memleak now. jmcd */
147 machine_ou = sstring_sub(lp_ldap_machine_suffix(), '=', ',');
148 fprintf(add_fd, "ou: %s\n", machine_ou);
149 SAFE_FREE(machine_ou);
150 fprintf(add_fd, "\n");
151 fflush(add_fd);
154 /* If it exists and is distinct from other containers,
155 Write the IdMap entity */
156 idmap_suffix = lp_ldap_idmap_suffix();
157 if (idmap_suffix == NULL) {
158 SAFE_FREE(suffix_attr);
159 SAFE_FREE(user_attr);
160 SAFE_FREE(group_attr);
161 return NT_STATUS_NO_MEMORY;
163 if (*idmap_suffix &&
164 strcmp(idmap_suffix, user_suffix) &&
165 strcmp(idmap_suffix, suffix)) {
166 char *s;
167 fprintf(add_fd, "# %s\n", idmap_suffix);
168 fprintf(add_fd, "dn: %s\n", idmap_suffix);
169 fprintf(add_fd, "ObjectClass: organizationalUnit\n");
170 s = sstring_sub(lp_ldap_idmap_suffix(), '=', ',');
171 fprintf(add_fd, "ou: %s\n", s);
172 SAFE_FREE(s);
173 fprintf(add_fd, "\n");
174 fflush(add_fd);
177 /* Write the domain entity */
178 fprintf(add_fd, "# %s, %s\n", lp_workgroup(), suffix);
179 fprintf(add_fd, "dn: sambaDomainName=%s,%s\n", lp_workgroup(),
180 suffix);
181 fprintf(add_fd, "objectClass: sambaDomain\n");
182 fprintf(add_fd, "objectClass: sambaUnixIdPool\n");
183 fprintf(add_fd, "sambaDomainName: %s\n", lp_workgroup());
184 fprintf(add_fd, "sambaSID: %s\n", sid);
185 fprintf(add_fd, "uidNumber: %d\n", ++ldif_uid);
186 fprintf(add_fd, "gidNumber: %d\n", ++ldif_gid);
187 fprintf(add_fd, "\n");
188 fflush(add_fd);
190 /* Write the Domain Admins entity */
191 fprintf(add_fd, "# Domain Admins, %s, %s\n", group_attr,
192 suffix);
193 fprintf(add_fd, "dn: cn=Domain Admins,ou=%s,%s\n", group_attr,
194 suffix);
195 fprintf(add_fd, "objectClass: posixGroup\n");
196 fprintf(add_fd, "objectClass: sambaGroupMapping\n");
197 fprintf(add_fd, "cn: Domain Admins\n");
198 fprintf(add_fd, "memberUid: Administrator\n");
199 fprintf(add_fd, "description: Netbios Domain Administrators\n");
200 fprintf(add_fd, "gidNumber: 512\n");
201 fprintf(add_fd, "sambaSID: %s-512\n", sid);
202 fprintf(add_fd, "sambaGroupType: 2\n");
203 fprintf(add_fd, "displayName: Domain Admins\n");
204 fprintf(add_fd, "\n");
205 fflush(add_fd);
207 /* Write the Domain Users entity */
208 fprintf(add_fd, "# Domain Users, %s, %s\n", group_attr,
209 suffix);
210 fprintf(add_fd, "dn: cn=Domain Users,ou=%s,%s\n", group_attr,
211 suffix);
212 fprintf(add_fd, "objectClass: posixGroup\n");
213 fprintf(add_fd, "objectClass: sambaGroupMapping\n");
214 fprintf(add_fd, "cn: Domain Users\n");
215 fprintf(add_fd, "description: Netbios Domain Users\n");
216 fprintf(add_fd, "gidNumber: 513\n");
217 fprintf(add_fd, "sambaSID: %s-513\n", sid);
218 fprintf(add_fd, "sambaGroupType: 2\n");
219 fprintf(add_fd, "displayName: Domain Users\n");
220 fprintf(add_fd, "\n");
221 fflush(add_fd);
223 /* Write the Domain Guests entity */
224 fprintf(add_fd, "# Domain Guests, %s, %s\n", group_attr,
225 suffix);
226 fprintf(add_fd, "dn: cn=Domain Guests,ou=%s,%s\n", group_attr,
227 suffix);
228 fprintf(add_fd, "objectClass: posixGroup\n");
229 fprintf(add_fd, "objectClass: sambaGroupMapping\n");
230 fprintf(add_fd, "cn: Domain Guests\n");
231 fprintf(add_fd, "description: Netbios Domain Guests\n");
232 fprintf(add_fd, "gidNumber: 514\n");
233 fprintf(add_fd, "sambaSID: %s-514\n", sid);
234 fprintf(add_fd, "sambaGroupType: 2\n");
235 fprintf(add_fd, "displayName: Domain Guests\n");
236 fprintf(add_fd, "\n");
237 fflush(add_fd);
239 /* Write the Domain Computers entity */
240 fprintf(add_fd, "# Domain Computers, %s, %s\n", group_attr,
241 suffix);
242 fprintf(add_fd, "dn: cn=Domain Computers,ou=%s,%s\n",
243 group_attr, suffix);
244 fprintf(add_fd, "objectClass: posixGroup\n");
245 fprintf(add_fd, "objectClass: sambaGroupMapping\n");
246 fprintf(add_fd, "gidNumber: 515\n");
247 fprintf(add_fd, "cn: Domain Computers\n");
248 fprintf(add_fd, "description: Netbios Domain Computers accounts\n");
249 fprintf(add_fd, "sambaSID: %s-515\n", sid);
250 fprintf(add_fd, "sambaGroupType: 2\n");
251 fprintf(add_fd, "displayName: Domain Computers\n");
252 fprintf(add_fd, "\n");
253 fflush(add_fd);
255 /* Write the Admininistrators Groups entity */
256 fprintf(add_fd, "# Administrators, %s, %s\n", group_attr,
257 suffix);
258 fprintf(add_fd, "dn: cn=Administrators,ou=%s,%s\n", group_attr,
259 suffix);
260 fprintf(add_fd, "objectClass: posixGroup\n");
261 fprintf(add_fd, "objectClass: sambaGroupMapping\n");
262 fprintf(add_fd, "gidNumber: 544\n");
263 fprintf(add_fd, "cn: Administrators\n");
264 fprintf(add_fd, "description: Netbios Domain Members can fully administer the computer/sambaDomainName\n");
265 fprintf(add_fd, "sambaSID: %s-544\n", builtin_sid);
266 fprintf(add_fd, "sambaGroupType: 5\n");
267 fprintf(add_fd, "displayName: Administrators\n");
268 fprintf(add_fd, "\n");
270 /* Write the Print Operator entity */
271 fprintf(add_fd, "# Print Operators, %s, %s\n", group_attr,
272 suffix);
273 fprintf(add_fd, "dn: cn=Print Operators,ou=%s,%s\n",
274 group_attr, suffix);
275 fprintf(add_fd, "objectClass: posixGroup\n");
276 fprintf(add_fd, "objectClass: sambaGroupMapping\n");
277 fprintf(add_fd, "gidNumber: 550\n");
278 fprintf(add_fd, "cn: Print Operators\n");
279 fprintf(add_fd, "description: Netbios Domain Print Operators\n");
280 fprintf(add_fd, "sambaSID: %s-550\n", builtin_sid);
281 fprintf(add_fd, "sambaGroupType: 5\n");
282 fprintf(add_fd, "displayName: Print Operators\n");
283 fprintf(add_fd, "\n");
284 fflush(add_fd);
286 /* Write the Backup Operators entity */
287 fprintf(add_fd, "# Backup Operators, %s, %s\n", group_attr,
288 suffix);
289 fprintf(add_fd, "dn: cn=Backup Operators,ou=%s,%s\n",
290 group_attr, suffix);
291 fprintf(add_fd, "objectClass: posixGroup\n");
292 fprintf(add_fd, "objectClass: sambaGroupMapping\n");
293 fprintf(add_fd, "gidNumber: 551\n");
294 fprintf(add_fd, "cn: Backup Operators\n");
295 fprintf(add_fd, "description: Netbios Domain Members can bypass file security to back up files\n");
296 fprintf(add_fd, "sambaSID: %s-551\n", builtin_sid);
297 fprintf(add_fd, "sambaGroupType: 5\n");
298 fprintf(add_fd, "displayName: Backup Operators\n");
299 fprintf(add_fd, "\n");
300 fflush(add_fd);
302 /* Write the Replicators entity */
303 fprintf(add_fd, "# Replicators, %s, %s\n", group_attr, suffix);
304 fprintf(add_fd, "dn: cn=Replicators,ou=%s,%s\n", group_attr,
305 suffix);
306 fprintf(add_fd, "objectClass: posixGroup\n");
307 fprintf(add_fd, "objectClass: sambaGroupMapping\n");
308 fprintf(add_fd, "gidNumber: 552\n");
309 fprintf(add_fd, "cn: Replicators\n");
310 fprintf(add_fd, "description: Netbios Domain Supports file replication in a sambaDomainName\n");
311 fprintf(add_fd, "sambaSID: %s-552\n", builtin_sid);
312 fprintf(add_fd, "sambaGroupType: 5\n");
313 fprintf(add_fd, "displayName: Replicators\n");
314 fprintf(add_fd, "\n");
315 fflush(add_fd);
317 /* Deallocate memory, and return */
318 SAFE_FREE(suffix_attr);
319 SAFE_FREE(user_attr);
320 SAFE_FREE(group_attr);
321 return NT_STATUS_OK;
324 /****************************************************************
325 ****************************************************************/
327 static NTSTATUS map_populate_groups(TALLOC_CTX *mem_ctx,
328 GROUPMAP *groupmap,
329 ACCOUNTMAP *accountmap,
330 const char *sid,
331 const char *suffix,
332 const char *builtin_sid)
334 char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
336 /* Map the groups created by populate_ldap_for_ldif */
337 groupmap[0].rid = 512;
338 groupmap[0].gidNumber = 512;
339 groupmap[0].sambaSID = talloc_asprintf(mem_ctx, "%s-512", sid);
340 groupmap[0].group_dn = talloc_asprintf(mem_ctx,
341 "cn=Domain Admins,ou=%s,%s", group_attr, suffix);
342 NT_STATUS_HAVE_NO_MEMORY(groupmap[0].sambaSID);
343 NT_STATUS_HAVE_NO_MEMORY(groupmap[0].group_dn);
345 accountmap[0].rid = 512;
346 accountmap[0].cn = talloc_strdup(mem_ctx, "Domain Admins");
347 NT_STATUS_HAVE_NO_MEMORY(accountmap[0].cn);
349 groupmap[1].rid = 513;
350 groupmap[1].gidNumber = 513;
351 groupmap[1].sambaSID = talloc_asprintf(mem_ctx, "%s-513", sid);
352 groupmap[1].group_dn = talloc_asprintf(mem_ctx,
353 "cn=Domain Users,ou=%s,%s", group_attr, suffix);
354 NT_STATUS_HAVE_NO_MEMORY(groupmap[1].sambaSID);
355 NT_STATUS_HAVE_NO_MEMORY(groupmap[1].group_dn);
357 accountmap[1].rid = 513;
358 accountmap[1].cn = talloc_strdup(mem_ctx, "Domain Users");
359 NT_STATUS_HAVE_NO_MEMORY(accountmap[1].cn);
361 groupmap[2].rid = 514;
362 groupmap[2].gidNumber = 514;
363 groupmap[2].sambaSID = talloc_asprintf(mem_ctx, "%s-514", sid);
364 groupmap[2].group_dn = talloc_asprintf(mem_ctx,
365 "cn=Domain Guests,ou=%s,%s", group_attr, suffix);
366 NT_STATUS_HAVE_NO_MEMORY(groupmap[2].sambaSID);
367 NT_STATUS_HAVE_NO_MEMORY(groupmap[2].group_dn);
369 accountmap[2].rid = 514;
370 accountmap[2].cn = talloc_strdup(mem_ctx, "Domain Guests");
371 NT_STATUS_HAVE_NO_MEMORY(accountmap[2].cn);
373 groupmap[3].rid = 515;
374 groupmap[3].gidNumber = 515;
375 groupmap[3].sambaSID = talloc_asprintf(mem_ctx, "%s-515", sid);
376 groupmap[3].group_dn = talloc_asprintf(mem_ctx,
377 "cn=Domain Computers,ou=%s,%s", group_attr, suffix);
378 NT_STATUS_HAVE_NO_MEMORY(groupmap[3].sambaSID);
379 NT_STATUS_HAVE_NO_MEMORY(groupmap[3].group_dn);
381 accountmap[3].rid = 515;
382 accountmap[3].cn = talloc_strdup(mem_ctx, "Domain Computers");
383 NT_STATUS_HAVE_NO_MEMORY(accountmap[3].cn);
385 groupmap[4].rid = 544;
386 groupmap[4].gidNumber = 544;
387 groupmap[4].sambaSID = talloc_asprintf(mem_ctx, "%s-544", builtin_sid);
388 groupmap[4].group_dn = talloc_asprintf(mem_ctx,
389 "cn=Administrators,ou=%s,%s", group_attr, suffix);
390 NT_STATUS_HAVE_NO_MEMORY(groupmap[4].sambaSID);
391 NT_STATUS_HAVE_NO_MEMORY(groupmap[4].group_dn);
393 accountmap[4].rid = 515;
394 accountmap[4].cn = talloc_strdup(mem_ctx, "Administrators");
395 NT_STATUS_HAVE_NO_MEMORY(accountmap[4].cn);
397 groupmap[5].rid = 550;
398 groupmap[5].gidNumber = 550;
399 groupmap[5].sambaSID = talloc_asprintf(mem_ctx, "%s-550", builtin_sid);
400 groupmap[5].group_dn = talloc_asprintf(mem_ctx,
401 "cn=Print Operators,ou=%s,%s", group_attr, suffix);
402 NT_STATUS_HAVE_NO_MEMORY(groupmap[5].sambaSID);
403 NT_STATUS_HAVE_NO_MEMORY(groupmap[5].group_dn);
405 accountmap[5].rid = 550;
406 accountmap[5].cn = talloc_strdup(mem_ctx, "Print Operators");
407 NT_STATUS_HAVE_NO_MEMORY(accountmap[5].cn);
409 groupmap[6].rid = 551;
410 groupmap[6].gidNumber = 551;
411 groupmap[6].sambaSID = talloc_asprintf(mem_ctx, "%s-551", builtin_sid);
412 groupmap[6].group_dn = talloc_asprintf(mem_ctx,
413 "cn=Backup Operators,ou=%s,%s", group_attr, suffix);
414 NT_STATUS_HAVE_NO_MEMORY(groupmap[6].sambaSID);
415 NT_STATUS_HAVE_NO_MEMORY(groupmap[6].group_dn);
417 accountmap[6].rid = 551;
418 accountmap[6].cn = talloc_strdup(mem_ctx, "Backup Operators");
419 NT_STATUS_HAVE_NO_MEMORY(accountmap[6].cn);
421 groupmap[7].rid = 552;
422 groupmap[7].gidNumber = 552;
423 groupmap[7].sambaSID = talloc_asprintf(mem_ctx, "%s-552", builtin_sid);
424 groupmap[7].group_dn = talloc_asprintf(mem_ctx,
425 "cn=Replicators,ou=%s,%s", group_attr, suffix);
426 NT_STATUS_HAVE_NO_MEMORY(groupmap[7].sambaSID);
427 NT_STATUS_HAVE_NO_MEMORY(groupmap[7].group_dn);
429 accountmap[7].rid = 551;
430 accountmap[7].cn = talloc_strdup(mem_ctx, "Replicators");
431 NT_STATUS_HAVE_NO_MEMORY(accountmap[7].cn);
433 SAFE_FREE(group_attr);
435 return NT_STATUS_OK;
439 * This is a crap routine, but I think it's the quickest way to solve the
440 * UTF8->base64 problem.
443 static int fprintf_attr(FILE *add_fd, const char *attr_name,
444 const char *fmt, ...)
446 va_list ap;
447 char *value, *p, *base64;
448 DATA_BLOB base64_blob;
449 bool do_base64 = false;
450 int res;
452 va_start(ap, fmt);
453 value = talloc_vasprintf(NULL, fmt, ap);
454 va_end(ap);
456 SMB_ASSERT(value != NULL);
458 for (p=value; *p; p++) {
459 if (*p & 0x80) {
460 do_base64 = true;
461 break;
465 if (!do_base64) {
466 bool only_whitespace = true;
467 for (p=value; *p; p++) {
469 * I know that this not multibyte safe, but we break
470 * on the first non-whitespace character anyway.
472 if (!isspace(*p)) {
473 only_whitespace = false;
474 break;
477 if (only_whitespace) {
478 do_base64 = true;
482 if (!do_base64) {
483 res = fprintf(add_fd, "%s: %s\n", attr_name, value);
484 TALLOC_FREE(value);
485 return res;
488 base64_blob.data = (unsigned char *)value;
489 base64_blob.length = strlen(value);
491 base64 = base64_encode_data_blob(value, base64_blob);
492 SMB_ASSERT(base64 != NULL);
494 res = fprintf(add_fd, "%s:: %s\n", attr_name, base64);
495 TALLOC_FREE(value);
496 return res;
499 /****************************************************************
500 ****************************************************************/
502 static NTSTATUS fetch_group_info_to_ldif(TALLOC_CTX *mem_ctx,
503 struct netr_DELTA_GROUP *r,
504 GROUPMAP *groupmap,
505 FILE *add_fd,
506 const char *sid,
507 const char *suffix)
509 const char *groupname = r->group_name.string;
510 uint32 grouptype = 0, g_rid = 0;
511 char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
513 /* Set up the group type (always 2 for group info) */
514 grouptype = 2;
516 /* These groups are entered by populate_ldap_for_ldif */
517 if (strcmp(groupname, "Domain Admins") == 0 ||
518 strcmp(groupname, "Domain Users") == 0 ||
519 strcmp(groupname, "Domain Guests") == 0 ||
520 strcmp(groupname, "Domain Computers") == 0 ||
521 strcmp(groupname, "Administrators") == 0 ||
522 strcmp(groupname, "Print Operators") == 0 ||
523 strcmp(groupname, "Backup Operators") == 0 ||
524 strcmp(groupname, "Replicators") == 0) {
525 SAFE_FREE(group_attr);
526 return NT_STATUS_OK;
527 } else {
528 /* Increment the gid for the new group */
529 ldif_gid++;
532 /* Map the group rid, gid, and dn */
533 g_rid = r->rid;
534 groupmap->rid = g_rid;
535 groupmap->gidNumber = ldif_gid;
536 groupmap->sambaSID = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
537 groupmap->group_dn = talloc_asprintf(mem_ctx,
538 "cn=%s,ou=%s,%s", groupname, group_attr, suffix);
539 NT_STATUS_HAVE_NO_MEMORY(groupmap->sambaSID);
540 NT_STATUS_HAVE_NO_MEMORY(groupmap->group_dn);
542 /* Write the data to the temporary add ldif file */
543 fprintf(add_fd, "# %s, %s, %s\n", groupname, group_attr,
544 suffix);
545 fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", groupname, group_attr,
546 suffix);
547 fprintf(add_fd, "objectClass: posixGroup\n");
548 fprintf(add_fd, "objectClass: sambaGroupMapping\n");
549 fprintf_attr(add_fd, "cn", "%s", groupname);
550 fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
551 fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
552 fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
553 fprintf_attr(add_fd, "displayName", "%s", groupname);
554 fprintf(add_fd, "\n");
555 fflush(add_fd);
557 SAFE_FREE(group_attr);
558 /* Return */
559 return NT_STATUS_OK;
562 /****************************************************************
563 ****************************************************************/
565 static NTSTATUS fetch_account_info_to_ldif(TALLOC_CTX *mem_ctx,
566 struct netr_DELTA_USER *r,
567 GROUPMAP *groupmap,
568 ACCOUNTMAP *accountmap,
569 FILE *add_fd,
570 const char *sid,
571 const char *suffix,
572 int alloced)
574 fstring username, logonscript, homedrive, homepath = "", homedir = "";
575 fstring hex_nt_passwd, hex_lm_passwd;
576 fstring description, profilepath, fullname, sambaSID;
577 uchar lm_passwd[16], nt_passwd[16];
578 char *flags, *user_rdn;
579 const char *ou;
580 const char* nopasswd = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
581 static uchar zero_buf[16];
582 uint32 rid = 0, group_rid = 0, gidNumber = 0;
583 time_t unix_time;
584 int i;
586 /* Get the username */
587 fstrcpy(username, r->account_name.string);
589 /* Get the rid */
590 rid = r->rid;
592 /* Map the rid and username for group member info later */
593 accountmap->rid = rid;
594 accountmap->cn = talloc_strdup(mem_ctx, username);
595 NT_STATUS_HAVE_NO_MEMORY(accountmap->cn);
597 /* Get the home directory */
598 if (r->acct_flags & ACB_NORMAL) {
599 fstrcpy(homedir, r->home_directory.string);
600 if (!*homedir) {
601 snprintf(homedir, sizeof(homedir), "/home/%s", username);
602 } else {
603 snprintf(homedir, sizeof(homedir), "/nobodyshomedir");
605 ou = lp_ldap_user_suffix();
606 } else {
607 ou = lp_ldap_machine_suffix();
608 snprintf(homedir, sizeof(homedir), "/machinehomedir");
611 /* Get the logon script */
612 fstrcpy(logonscript, r->logon_script.string);
614 /* Get the home drive */
615 fstrcpy(homedrive, r->home_drive.string);
617 /* Get the home path */
618 fstrcpy(homepath, r->home_directory.string);
620 /* Get the description */
621 fstrcpy(description, r->description.string);
623 /* Get the display name */
624 fstrcpy(fullname, r->full_name.string);
626 /* Get the profile path */
627 fstrcpy(profilepath, r->profile_path.string);
629 /* Get lm and nt password data */
630 if (memcmp(r->lmpassword.hash, zero_buf, 16) != 0) {
631 sam_pwd_hash(r->rid, r->lmpassword.hash, lm_passwd, 0);
632 pdb_sethexpwd(hex_lm_passwd, lm_passwd, r->acct_flags);
633 } else {
634 pdb_sethexpwd(hex_lm_passwd, NULL, 0);
636 if (memcmp(r->ntpassword.hash, zero_buf, 16) != 0) {
637 sam_pwd_hash(r->rid, r->ntpassword.hash, nt_passwd, 0);
638 pdb_sethexpwd(hex_nt_passwd, nt_passwd, r->acct_flags);
639 } else {
640 pdb_sethexpwd(hex_nt_passwd, NULL, 0);
642 unix_time = nt_time_to_unix(r->last_password_change);
644 /* Increment the uid for the new user */
645 ldif_uid++;
647 /* Set up group id and sambaSID for the user */
648 group_rid = r->primary_gid;
649 for (i=0; i<alloced; i++) {
650 if (groupmap[i].rid == group_rid) break;
652 if (i == alloced){
653 DEBUG(1, ("Could not find rid %d in groupmap array\n",
654 group_rid));
655 return NT_STATUS_UNSUCCESSFUL;
657 gidNumber = groupmap[i].gidNumber;
658 snprintf(sambaSID, sizeof(sambaSID), groupmap[i].sambaSID);
660 /* Set up sambaAcctFlags */
661 flags = pdb_encode_acct_ctrl(r->acct_flags,
662 NEW_PW_FORMAT_SPACE_PADDED_LEN);
664 /* Add the user to the temporary add ldif file */
665 /* this isn't quite right...we can't assume there's just OU=. jmcd */
666 user_rdn = sstring_sub(ou, '=', ',');
667 fprintf(add_fd, "# %s, %s, %s\n", username, user_rdn, suffix);
668 fprintf_attr(add_fd, "dn", "uid=%s,ou=%s,%s", username, user_rdn,
669 suffix);
670 SAFE_FREE(user_rdn);
671 fprintf(add_fd, "ObjectClass: top\n");
672 fprintf(add_fd, "objectClass: inetOrgPerson\n");
673 fprintf(add_fd, "objectClass: posixAccount\n");
674 fprintf(add_fd, "objectClass: shadowAccount\n");
675 fprintf(add_fd, "objectClass: sambaSamAccount\n");
676 fprintf_attr(add_fd, "cn", "%s", username);
677 fprintf_attr(add_fd, "sn", "%s", username);
678 fprintf_attr(add_fd, "uid", "%s", username);
679 fprintf(add_fd, "uidNumber: %d\n", ldif_uid);
680 fprintf(add_fd, "gidNumber: %d\n", gidNumber);
681 fprintf_attr(add_fd, "homeDirectory", "%s", homedir);
682 if (*homepath)
683 fprintf_attr(add_fd, "sambaHomePath", "%s", homepath);
684 if (*homedrive)
685 fprintf_attr(add_fd, "sambaHomeDrive", "%s", homedrive);
686 if (*logonscript)
687 fprintf_attr(add_fd, "sambaLogonScript", "%s", logonscript);
688 fprintf(add_fd, "loginShell: %s\n",
689 ((r->acct_flags & ACB_NORMAL) ?
690 "/bin/bash" : "/bin/false"));
691 fprintf(add_fd, "gecos: System User\n");
692 if (*description)
693 fprintf_attr(add_fd, "description", "%s", description);
694 fprintf(add_fd, "sambaSID: %s-%d\n", sid, rid);
695 fprintf(add_fd, "sambaPrimaryGroupSID: %s\n", sambaSID);
696 if(*fullname)
697 fprintf_attr(add_fd, "displayName", "%s", fullname);
698 if(*profilepath)
699 fprintf_attr(add_fd, "sambaProfilePath", "%s", profilepath);
700 if (strcmp(nopasswd, hex_lm_passwd) != 0)
701 fprintf(add_fd, "sambaLMPassword: %s\n", hex_lm_passwd);
702 if (strcmp(nopasswd, hex_nt_passwd) != 0)
703 fprintf(add_fd, "sambaNTPassword: %s\n", hex_nt_passwd);
704 fprintf(add_fd, "sambaPwdLastSet: %d\n", (int)unix_time);
705 fprintf(add_fd, "sambaAcctFlags: %s\n", flags);
706 fprintf(add_fd, "\n");
707 fflush(add_fd);
709 /* Return */
710 return NT_STATUS_OK;
713 /****************************************************************
714 ****************************************************************/
716 static NTSTATUS fetch_alias_info_to_ldif(TALLOC_CTX *mem_ctx,
717 struct netr_DELTA_ALIAS *r,
718 GROUPMAP *groupmap,
719 FILE *add_fd,
720 const char *sid,
721 const char *suffix,
722 enum netr_SamDatabaseID database_id)
724 fstring aliasname, description;
725 uint32 grouptype = 0, g_rid = 0;
726 char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
728 /* Get the alias name */
729 fstrcpy(aliasname, r->alias_name.string);
731 /* Get the alias description */
732 fstrcpy(description, r->description.string);
734 /* Set up the group type */
735 switch (database_id) {
736 case SAM_DATABASE_DOMAIN:
737 grouptype = 4;
738 break;
739 case SAM_DATABASE_BUILTIN:
740 grouptype = 5;
741 break;
742 default:
743 grouptype = 4;
744 break;
748 These groups are entered by populate_ldap_for_ldif
749 Note that populate creates a group called Relicators,
750 but NT returns a group called Replicator
752 if (strcmp(aliasname, "Domain Admins") == 0 ||
753 strcmp(aliasname, "Domain Users") == 0 ||
754 strcmp(aliasname, "Domain Guests") == 0 ||
755 strcmp(aliasname, "Domain Computers") == 0 ||
756 strcmp(aliasname, "Administrators") == 0 ||
757 strcmp(aliasname, "Print Operators") == 0 ||
758 strcmp(aliasname, "Backup Operators") == 0 ||
759 strcmp(aliasname, "Replicator") == 0) {
760 SAFE_FREE(group_attr);
761 return NT_STATUS_OK;
762 } else {
763 /* Increment the gid for the new group */
764 ldif_gid++;
767 /* Map the group rid and gid */
768 g_rid = r->rid;
769 groupmap->gidNumber = ldif_gid;
770 groupmap->sambaSID = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
771 NT_STATUS_HAVE_NO_MEMORY(groupmap->sambaSID);
773 /* Write the data to the temporary add ldif file */
774 fprintf(add_fd, "# %s, %s, %s\n", aliasname, group_attr,
775 suffix);
776 fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", aliasname, group_attr,
777 suffix);
778 fprintf(add_fd, "objectClass: posixGroup\n");
779 fprintf(add_fd, "objectClass: sambaGroupMapping\n");
780 fprintf(add_fd, "cn: %s\n", aliasname);
781 fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
782 fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
783 fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
784 fprintf_attr(add_fd, "displayName", "%s", aliasname);
785 if (description[0])
786 fprintf_attr(add_fd, "description", "%s", description);
787 fprintf(add_fd, "\n");
788 fflush(add_fd);
790 SAFE_FREE(group_attr);
791 /* Return */
792 return NT_STATUS_OK;
795 /****************************************************************
796 ****************************************************************/
798 static NTSTATUS fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER *r,
799 uint32_t id_rid,
800 GROUPMAP *groupmap,
801 ACCOUNTMAP *accountmap,
802 FILE *mod_fd, int alloced)
804 fstring group_dn;
805 uint32 group_rid = 0, rid = 0;
806 int i, j, k;
808 /* Get the dn for the group */
809 if (r->num_rids > 0) {
810 group_rid = id_rid;
811 for (j=0; j<alloced; j++) {
812 if (groupmap[j].rid == group_rid) break;
814 if (j == alloced){
815 DEBUG(1, ("Could not find rid %d in groupmap array\n",
816 group_rid));
817 return NT_STATUS_UNSUCCESSFUL;
819 snprintf(group_dn, sizeof(group_dn), "%s", groupmap[j].group_dn);
820 fprintf(mod_fd, "dn: %s\n", group_dn);
822 /* Get the cn for each member */
823 for (i=0; i < r->num_rids; i++) {
824 rid = r->rids[i];
825 for (k=0; k<alloced; k++) {
826 if (accountmap[k].rid == rid) break;
828 if (k == alloced){
829 DEBUG(1, ("Could not find rid %d in "
830 "accountmap array\n", rid));
831 return NT_STATUS_UNSUCCESSFUL;
833 fprintf(mod_fd, "memberUid: %s\n", accountmap[k].cn);
835 fprintf(mod_fd, "\n");
837 fflush(mod_fd);
839 /* Return */
840 return NT_STATUS_OK;
843 /****************************************************************
844 ****************************************************************/
846 static NTSTATUS ldif_init_context(TALLOC_CTX *mem_ctx,
847 enum netr_SamDatabaseID database_id,
848 const char *ldif_filename,
849 const char *domain_sid_str,
850 struct samsync_ldif_context **ctx)
852 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
853 struct samsync_ldif_context *r;
854 const char *add_template = "/tmp/add.ldif.XXXXXX";
855 const char *mod_template = "/tmp/mod.ldif.XXXXXX";
856 const char *builtin_sid = "S-1-5-32";
858 /* Get other smb.conf data */
859 if (!(lp_workgroup()) || !*(lp_workgroup())) {
860 DEBUG(0,("workgroup missing from smb.conf--exiting\n"));
861 exit(1);
864 /* Get the ldap suffix */
865 if (!(lp_ldap_suffix()) || !*(lp_ldap_suffix())) {
866 DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
867 exit(1);
870 if (*ctx && (*ctx)->initialized) {
871 return NT_STATUS_OK;
874 r = TALLOC_ZERO_P(mem_ctx, struct samsync_ldif_context);
875 NT_STATUS_HAVE_NO_MEMORY(r);
877 /* Get the ldap suffix */
878 r->suffix = lp_ldap_suffix();
880 /* Ensure we have an output file */
881 if (ldif_filename) {
882 r->ldif_file = fopen(ldif_filename, "a");
883 } else {
884 r->ldif_file = stdout;
887 if (!r->ldif_file) {
888 fprintf(stderr, "Could not open %s\n", ldif_filename);
889 DEBUG(1, ("Could not open %s\n", ldif_filename));
890 status = NT_STATUS_UNSUCCESSFUL;
891 goto done;
894 r->add_template = talloc_strdup(mem_ctx, add_template);
895 r->mod_template = talloc_strdup(mem_ctx, mod_template);
896 if (!r->add_template || !r->mod_template) {
897 status = NT_STATUS_NO_MEMORY;
898 goto done;
901 r->add_name = talloc_strdup(mem_ctx, add_template);
902 r->mod_name = talloc_strdup(mem_ctx, mod_template);
903 if (!r->add_name || !r->mod_name) {
904 status = NT_STATUS_NO_MEMORY;
905 goto done;
908 /* Open the add and mod ldif files */
909 if (!(r->add_file = fdopen(smb_mkstemp(r->add_name),"w"))) {
910 DEBUG(1, ("Could not open %s\n", r->add_name));
911 status = NT_STATUS_UNSUCCESSFUL;
912 goto done;
914 if (!(r->mod_file = fdopen(smb_mkstemp(r->mod_name),"w"))) {
915 DEBUG(1, ("Could not open %s\n", r->mod_name));
916 status = NT_STATUS_UNSUCCESSFUL;
917 goto done;
920 /* Allocate initial memory for groupmap and accountmap arrays */
921 r->groupmap = TALLOC_ZERO_ARRAY(mem_ctx, GROUPMAP, 8);
922 r->accountmap = TALLOC_ZERO_ARRAY(mem_ctx, ACCOUNTMAP, 8);
923 if (r->groupmap == NULL || r->accountmap == NULL) {
924 DEBUG(1,("GROUPMAP talloc failed\n"));
925 status = NT_STATUS_NO_MEMORY;
926 goto done;
929 /* Remember how many we malloced */
930 r->num_alloced = 8;
932 /* Initial database population */
933 if (database_id == SAM_DATABASE_DOMAIN) {
935 status = populate_ldap_for_ldif(domain_sid_str,
936 r->suffix,
937 builtin_sid,
938 r->add_file);
939 if (!NT_STATUS_IS_OK(status)) {
940 goto done;
943 status = map_populate_groups(mem_ctx,
944 r->groupmap,
945 r->accountmap,
946 domain_sid_str,
947 r->suffix,
948 builtin_sid);
949 if (!NT_STATUS_IS_OK(status)) {
950 goto done;
954 r->initialized = true;
956 *ctx = r;
958 return NT_STATUS_OK;
959 done:
960 TALLOC_FREE(r);
961 return status;
964 /****************************************************************
965 ****************************************************************/
967 static void ldif_free_context(struct samsync_ldif_context *r)
969 if (!r) {
970 return;
973 /* Close and delete the ldif files */
974 if (r->add_file) {
975 fclose(r->add_file);
978 if ((r->add_name != NULL) &&
979 strcmp(r->add_name, r->add_template) && (unlink(r->add_name))) {
980 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
981 r->add_name, strerror(errno)));
984 if (r->mod_file) {
985 fclose(r->mod_file);
988 if ((r->mod_name != NULL) &&
989 strcmp(r->mod_name, r->mod_template) && (unlink(r->mod_name))) {
990 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
991 r->mod_name, strerror(errno)));
994 if (r->ldif_file && (r->ldif_file != stdout)) {
995 fclose(r->ldif_file);
998 TALLOC_FREE(r);
1001 /****************************************************************
1002 ****************************************************************/
1004 static void ldif_write_output(enum netr_SamDatabaseID database_id,
1005 struct samsync_ldif_context *l)
1007 /* Write ldif data to the user's file */
1008 if (database_id == SAM_DATABASE_DOMAIN) {
1009 fprintf(l->ldif_file,
1010 "# SAM_DATABASE_DOMAIN: ADD ENTITIES\n");
1011 fprintf(l->ldif_file,
1012 "# =================================\n\n");
1013 fflush(l->ldif_file);
1014 } else if (database_id == SAM_DATABASE_BUILTIN) {
1015 fprintf(l->ldif_file,
1016 "# SAM_DATABASE_BUILTIN: ADD ENTITIES\n");
1017 fprintf(l->ldif_file,
1018 "# ==================================\n\n");
1019 fflush(l->ldif_file);
1021 fseek(l->add_file, 0, SEEK_SET);
1022 transfer_file(fileno(l->add_file), fileno(l->ldif_file), (size_t) -1);
1024 if (database_id == SAM_DATABASE_DOMAIN) {
1025 fprintf(l->ldif_file,
1026 "# SAM_DATABASE_DOMAIN: MODIFY ENTITIES\n");
1027 fprintf(l->ldif_file,
1028 "# ====================================\n\n");
1029 fflush(l->ldif_file);
1030 } else if (database_id == SAM_DATABASE_BUILTIN) {
1031 fprintf(l->ldif_file,
1032 "# SAM_DATABASE_BUILTIN: MODIFY ENTITIES\n");
1033 fprintf(l->ldif_file,
1034 "# =====================================\n\n");
1035 fflush(l->ldif_file);
1037 fseek(l->mod_file, 0, SEEK_SET);
1038 transfer_file(fileno(l->mod_file), fileno(l->ldif_file), (size_t) -1);
1041 /****************************************************************
1042 ****************************************************************/
1044 static NTSTATUS fetch_sam_entry_ldif(TALLOC_CTX *mem_ctx,
1045 enum netr_SamDatabaseID database_id,
1046 struct netr_DELTA_ENUM *r,
1047 struct samsync_context *ctx,
1048 uint32_t *a_index,
1049 uint32_t *g_index)
1051 union netr_DELTA_UNION u = r->delta_union;
1052 union netr_DELTA_ID_UNION id = r->delta_id_union;
1053 struct samsync_ldif_context *l =
1054 talloc_get_type_abort(ctx->private_data, struct samsync_ldif_context);
1056 switch (r->delta_type) {
1057 case NETR_DELTA_DOMAIN:
1058 break;
1060 case NETR_DELTA_GROUP:
1061 fetch_group_info_to_ldif(mem_ctx,
1062 u.group,
1063 &l->groupmap[*g_index],
1064 l->add_file,
1065 ctx->domain_sid_str,
1066 l->suffix);
1067 (*g_index)++;
1068 break;
1070 case NETR_DELTA_USER:
1071 fetch_account_info_to_ldif(mem_ctx,
1072 u.user,
1073 l->groupmap,
1074 &l->accountmap[*a_index],
1075 l->add_file,
1076 ctx->domain_sid_str,
1077 l->suffix,
1078 l->num_alloced);
1079 (*a_index)++;
1080 break;
1082 case NETR_DELTA_ALIAS:
1083 fetch_alias_info_to_ldif(mem_ctx,
1084 u.alias,
1085 &l->groupmap[*g_index],
1086 l->add_file,
1087 ctx->domain_sid_str,
1088 l->suffix,
1089 database_id);
1090 (*g_index)++;
1091 break;
1093 case NETR_DELTA_GROUP_MEMBER:
1094 fetch_groupmem_info_to_ldif(u.group_member,
1095 id.rid,
1096 l->groupmap,
1097 l->accountmap,
1098 l->mod_file,
1099 l->num_alloced);
1100 break;
1102 case NETR_DELTA_ALIAS_MEMBER:
1103 case NETR_DELTA_POLICY:
1104 case NETR_DELTA_ACCOUNT:
1105 case NETR_DELTA_TRUSTED_DOMAIN:
1106 case NETR_DELTA_SECRET:
1107 case NETR_DELTA_RENAME_GROUP:
1108 case NETR_DELTA_RENAME_USER:
1109 case NETR_DELTA_RENAME_ALIAS:
1110 case NETR_DELTA_DELETE_GROUP:
1111 case NETR_DELTA_DELETE_USER:
1112 case NETR_DELTA_MODIFY_COUNT:
1113 default:
1114 break;
1115 } /* end of switch */
1117 return NT_STATUS_OK;
1120 /****************************************************************
1121 ****************************************************************/
1123 static NTSTATUS ldif_realloc_maps(TALLOC_CTX *mem_ctx,
1124 struct samsync_ldif_context *l,
1125 uint32_t num_entries)
1127 /* Re-allocate memory for groupmap and accountmap arrays */
1128 l->groupmap = TALLOC_REALLOC_ARRAY(mem_ctx,
1129 l->groupmap,
1130 GROUPMAP,
1131 num_entries + l->num_alloced);
1133 l->accountmap = TALLOC_REALLOC_ARRAY(mem_ctx,
1134 l->accountmap,
1135 ACCOUNTMAP,
1136 num_entries + l->num_alloced);
1138 if (l->groupmap == NULL || l->accountmap == NULL) {
1139 DEBUG(1,("GROUPMAP talloc failed\n"));
1140 return NT_STATUS_NO_MEMORY;
1143 /* Initialize the new records */
1144 memset(&(l->groupmap[l->num_alloced]), 0,
1145 sizeof(GROUPMAP) * num_entries);
1146 memset(&(l->accountmap[l->num_alloced]), 0,
1147 sizeof(ACCOUNTMAP) * num_entries);
1149 /* Remember how many we alloced this time */
1150 l->num_alloced += num_entries;
1152 return NT_STATUS_OK;
1155 /****************************************************************
1156 ****************************************************************/
1158 NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
1159 enum netr_SamDatabaseID database_id,
1160 struct netr_DELTA_ENUM_ARRAY *r,
1161 bool last_query,
1162 struct samsync_context *ctx)
1164 NTSTATUS status;
1165 int i;
1166 uint32_t g_index = 0, a_index = 0;
1167 struct samsync_ldif_context *ldif_ctx =
1168 (struct samsync_ldif_context *)ctx->private_data;
1170 status = ldif_init_context(mem_ctx,
1171 database_id,
1172 ctx->output_filename,
1173 ctx->domain_sid_str,
1174 &ldif_ctx);
1175 if (!NT_STATUS_IS_OK(status)) {
1176 goto failed;
1179 ctx->private_data = ldif_ctx;
1181 status = ldif_realloc_maps(mem_ctx, ldif_ctx, r->num_deltas);
1182 if (!NT_STATUS_IS_OK(status)) {
1183 goto failed;
1186 for (i = 0; i < r->num_deltas; i++) {
1187 status = fetch_sam_entry_ldif(mem_ctx, database_id,
1188 &r->delta_enum[i], ctx,
1189 &a_index, &g_index);
1190 if (!NT_STATUS_IS_OK(status)) {
1191 goto failed;
1195 /* This was the last query */
1196 if (last_query) {
1197 ldif_write_output(database_id, ldif_ctx);
1198 if (ldif_ctx->ldif_file != stdout) {
1199 ctx->result_message = talloc_asprintf(mem_ctx,
1200 "Vampired %d accounts and %d groups to %s",
1201 a_index, g_index, ctx->output_filename);
1203 ldif_free_context(ldif_ctx);
1204 ctx->private_data = NULL;
1207 return NT_STATUS_OK;
1209 failed:
1210 ldif_free_context(ldif_ctx);
1211 ctx->private_data = NULL;
1213 return status;