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/>.
27 #include "system/filesys.h"
28 #include "libnet/libnet_samsync.h"
29 #include "transfer_file.h"
31 #include "passdb/pdb_ldap_schema.h"
32 #include "lib/util/base64.h"
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;
41 static uint32_t g_index = 0;
42 static uint32_t a_index = 0;
44 /* Structure for mapping accounts to groups */
45 /* Array element is the group rid */
46 typedef struct _groupmap {
53 typedef struct _accountmap {
58 struct samsync_ldif_context {
60 ACCOUNTMAP *accountmap;
62 const char *add_template;
63 const char *mod_template;
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.
79 static char *sstring_sub(const char *src, char front, char back)
81 char *temp1, *temp2, *temp3;
84 temp1 = strchr(src, front);
85 if (temp1 == NULL) return NULL;
86 temp2 = strchr(src, back);
87 if (temp2 == NULL) return NULL;
89 if (len <= 0) return NULL;
90 temp3 = (char*)SMB_MALLOC(len);
92 DEBUG(1,("Malloc failure in sstring_sub\n"));
95 memcpy(temp3, temp1+1, len-1);
100 /****************************************************************
101 ****************************************************************/
103 static NTSTATUS populate_ldap_for_ldif(const char *sid,
105 const char *builtin_sid,
108 const char *user_suffix, *group_suffix, *machine_suffix, *idmap_suffix;
109 char *user_attr=NULL, *group_attr=NULL;
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);
119 return NT_STATUS_NO_MEMORY;
121 memcpy(suffix_attr, suffix, len);
122 suffix_attr[len] = '\0';
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");
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;
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");
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;
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");
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;
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");
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;
205 strcmp(idmap_suffix, user_suffix) &&
206 strcmp(idmap_suffix, suffix)) {
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);
214 fprintf(add_fd, "\n");
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(),
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");
231 /* Write the Domain Admins entity */
232 fprintf(add_fd, "# Domain Admins, %s, %s\n", group_attr,
234 fprintf(add_fd, "dn: cn=Domain Admins,ou=%s,%s\n", group_attr,
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");
248 /* Write the Domain Users entity */
249 fprintf(add_fd, "# Domain Users, %s, %s\n", group_attr,
251 fprintf(add_fd, "dn: cn=Domain Users,ou=%s,%s\n", group_attr,
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");
264 /* Write the Domain Guests entity */
265 fprintf(add_fd, "# Domain Guests, %s, %s\n", group_attr,
267 fprintf(add_fd, "dn: cn=Domain Guests,ou=%s,%s\n", group_attr,
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");
280 /* Write the Domain Computers entity */
281 fprintf(add_fd, "# Domain Computers, %s, %s\n", group_attr,
283 fprintf(add_fd, "dn: cn=Domain Computers,ou=%s,%s\n",
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");
296 /* Write the Admininistrators Groups entity */
297 fprintf(add_fd, "# Administrators, %s, %s\n", group_attr,
299 fprintf(add_fd, "dn: cn=Administrators,ou=%s,%s\n", group_attr,
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");
311 /* Write the Print Operator entity */
312 fprintf(add_fd, "# Print Operators, %s, %s\n", group_attr,
314 fprintf(add_fd, "dn: cn=Print Operators,ou=%s,%s\n",
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");
327 /* Write the Backup Operators entity */
328 fprintf(add_fd, "# Backup Operators, %s, %s\n", group_attr,
330 fprintf(add_fd, "dn: cn=Backup Operators,ou=%s,%s\n",
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");
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,
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");
358 /* Deallocate memory, and return */
359 SAFE_FREE(suffix_attr);
360 SAFE_FREE(user_attr);
361 SAFE_FREE(group_attr);
365 /****************************************************************
366 ****************************************************************/
368 static NTSTATUS map_populate_groups(TALLOC_CTX *mem_ctx,
370 ACCOUNTMAP *accountmap,
373 const char *builtin_sid)
375 char *group_attr = sstring_sub(lp_ldap_group_suffix(talloc_tos()), '=', ',');
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) {
387 accountmap[0].rid = 512;
388 accountmap[0].cn = talloc_strdup(mem_ctx, "Domain Admins");
389 if (accountmap[0].cn == NULL) {
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) {
402 accountmap[1].rid = 513;
403 accountmap[1].cn = talloc_strdup(mem_ctx, "Domain Users");
404 if (accountmap[1].cn == NULL) {
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) {
417 accountmap[2].rid = 514;
418 accountmap[2].cn = talloc_strdup(mem_ctx, "Domain Guests");
419 if (accountmap[2].cn == NULL) {
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) {
432 accountmap[3].rid = 515;
433 accountmap[3].cn = talloc_strdup(mem_ctx, "Domain Computers");
434 if (accountmap[3].cn == NULL) {
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) {
447 accountmap[4].rid = 515;
448 accountmap[4].cn = talloc_strdup(mem_ctx, "Administrators");
449 if (accountmap[4].cn == NULL) {
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) {
462 accountmap[5].rid = 550;
463 accountmap[5].cn = talloc_strdup(mem_ctx, "Print Operators");
464 if (accountmap[5].cn == NULL) {
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) {
477 accountmap[6].rid = 551;
478 accountmap[6].cn = talloc_strdup(mem_ctx, "Backup Operators");
479 if (accountmap[6].cn == NULL) {
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) {
492 accountmap[7].rid = 551;
493 accountmap[7].cn = talloc_strdup(mem_ctx, "Replicators");
494 if (accountmap[7].cn == NULL) {
498 SAFE_FREE(group_attr);
504 SAFE_FREE(group_attr);
505 return NT_STATUS_NO_MEMORY;
509 * This is a crap routine, but I think it's the quickest way to solve the
510 * UTF8->base64 problem.
513 static int fprintf_attr(FILE *add_fd, const char *attr_name,
514 const char *fmt, ...)
517 char *value, *p, *base64;
518 DATA_BLOB base64_blob;
519 bool do_base64 = false;
523 value = talloc_vasprintf(NULL, fmt, ap);
526 SMB_ASSERT(value != NULL);
528 for (p=value; *p; p++) {
536 bool only_whitespace = true;
537 for (p=value; *p; p++) {
539 * I know that this not multibyte safe, but we break
540 * on the first non-whitespace character anyway.
543 only_whitespace = false;
547 if (only_whitespace) {
553 res = fprintf(add_fd, "%s: %s\n", attr_name, value);
558 base64_blob.data = (unsigned char *)value;
559 base64_blob.length = strlen(value);
561 base64 = base64_encode_data_blob(value, base64_blob);
562 SMB_ASSERT(base64 != NULL);
564 res = fprintf(add_fd, "%s:: %s\n", attr_name, base64);
569 /****************************************************************
570 ****************************************************************/
572 static NTSTATUS fetch_group_info_to_ldif(TALLOC_CTX *mem_ctx,
573 struct netr_DELTA_GROUP *r,
579 const char *groupname = r->group_name.string;
580 uint32_t grouptype = 0, g_rid = 0;
581 char *group_attr = sstring_sub(lp_ldap_group_suffix(talloc_tos()), '=', ',');
583 /* Set up the group type (always 2 for group info) */
586 /* These groups are entered by populate_ldap_for_ldif */
587 if (strcmp(groupname, "Domain Admins") == 0 ||
588 strcmp(groupname, "Domain Users") == 0 ||
589 strcmp(groupname, "Domain Guests") == 0 ||
590 strcmp(groupname, "Domain Computers") == 0 ||
591 strcmp(groupname, "Administrators") == 0 ||
592 strcmp(groupname, "Print Operators") == 0 ||
593 strcmp(groupname, "Backup Operators") == 0 ||
594 strcmp(groupname, "Replicators") == 0) {
595 SAFE_FREE(group_attr);
598 /* Increment the gid for the new group */
602 /* Map the group rid, gid, and dn */
604 groupmap->rid = g_rid;
605 groupmap->gidNumber = ldif_gid;
606 groupmap->sambaSID = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
607 groupmap->group_dn = talloc_asprintf(mem_ctx,
608 "cn=%s,ou=%s,%s", groupname, group_attr, suffix);
609 if (groupmap->sambaSID == NULL || groupmap->group_dn == NULL) {
610 SAFE_FREE(group_attr);
611 return NT_STATUS_NO_MEMORY;
614 /* Write the data to the temporary add ldif file */
615 fprintf(add_fd, "# %s, %s, %s\n", groupname, group_attr,
617 fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", groupname, group_attr,
619 fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
620 fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
621 fprintf_attr(add_fd, "cn", "%s", groupname);
622 fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
623 fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
624 fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
625 fprintf_attr(add_fd, "displayName", "%s", groupname);
626 fprintf(add_fd, "\n");
629 SAFE_FREE(group_attr);
634 /****************************************************************
635 ****************************************************************/
637 static NTSTATUS fetch_account_info_to_ldif(TALLOC_CTX *mem_ctx,
638 struct netr_DELTA_USER *r,
640 ACCOUNTMAP *accountmap,
646 fstring username, logonscript, homedrive, homepath = "", homedir = "";
647 fstring hex_nt_passwd, hex_lm_passwd;
648 fstring description, profilepath, fullname, sambaSID;
649 char *flags, *user_rdn;
651 const char* nopasswd = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
653 uint32_t rid = 0, group_rid = 0, gidNumber = 0;
657 memset(zero_buf, '\0', sizeof(zero_buf));
659 /* Get the username */
660 fstrcpy(username, r->account_name.string);
665 /* Map the rid and username for group member info later */
666 accountmap->rid = rid;
667 accountmap->cn = talloc_strdup(mem_ctx, username);
668 NT_STATUS_HAVE_NO_MEMORY(accountmap->cn);
670 /* Get the home directory */
671 if (r->acct_flags & ACB_NORMAL) {
672 fstrcpy(homedir, r->home_directory.string);
674 snprintf(homedir, sizeof(homedir), "/home/%s", username);
676 snprintf(homedir, sizeof(homedir), "/nobodyshomedir");
678 ou = lp_ldap_user_suffix(talloc_tos());
680 ou = lp_ldap_machine_suffix(talloc_tos());
681 snprintf(homedir, sizeof(homedir), "/machinehomedir");
684 /* Get the logon script */
685 fstrcpy(logonscript, r->logon_script.string);
687 /* Get the home drive */
688 fstrcpy(homedrive, r->home_drive.string);
690 /* Get the home path */
691 fstrcpy(homepath, r->home_directory.string);
693 /* Get the description */
694 fstrcpy(description, r->description.string);
696 /* Get the display name */
697 fstrcpy(fullname, r->full_name.string);
699 /* Get the profile path */
700 fstrcpy(profilepath, r->profile_path.string);
702 /* Get lm and nt password data */
703 if (memcmp(r->lmpassword.hash, zero_buf, 16) != 0) {
704 pdb_sethexpwd(hex_lm_passwd, r->lmpassword.hash, r->acct_flags);
706 pdb_sethexpwd(hex_lm_passwd, NULL, 0);
708 if (memcmp(r->ntpassword.hash, zero_buf, 16) != 0) {
709 pdb_sethexpwd(hex_nt_passwd, r->ntpassword.hash, r->acct_flags);
711 pdb_sethexpwd(hex_nt_passwd, NULL, 0);
713 unix_time = nt_time_to_unix(r->last_password_change);
715 /* Increment the uid for the new user */
718 /* Set up group id and sambaSID for the user */
719 group_rid = r->primary_gid;
720 for (i=0; i<alloced; i++) {
721 if (groupmap[i].rid == group_rid) break;
724 DEBUG(1, ("Could not find rid %d in groupmap array\n",
726 return NT_STATUS_UNSUCCESSFUL;
728 gidNumber = groupmap[i].gidNumber;
729 ret = snprintf(sambaSID, sizeof(sambaSID), "%s", groupmap[i].sambaSID);
730 if (ret < 0 || ret == sizeof(sambaSID)) {
731 return NT_STATUS_UNSUCCESSFUL;
734 /* Set up sambaAcctFlags */
735 flags = pdb_encode_acct_ctrl(r->acct_flags,
736 NEW_PW_FORMAT_SPACE_PADDED_LEN);
738 /* Add the user to the temporary add ldif file */
739 /* this isn't quite right...we can't assume there's just OU=. jmcd */
740 user_rdn = sstring_sub(ou, '=', ',');
741 fprintf(add_fd, "# %s, %s, %s\n", username, user_rdn, suffix);
742 fprintf_attr(add_fd, "dn", "uid=%s,ou=%s,%s", username, user_rdn,
745 fprintf(add_fd, "ObjectClass: top\n");
746 fprintf(add_fd, "objectClass: inetOrgPerson\n");
747 fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXACCOUNT);
748 fprintf(add_fd, "objectClass: shadowAccount\n");
749 fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_SAMBASAMACCOUNT);
750 fprintf_attr(add_fd, "cn", "%s", username);
751 fprintf_attr(add_fd, "sn", "%s", username);
752 fprintf_attr(add_fd, "uid", "%s", username);
753 fprintf(add_fd, "uidNumber: %d\n", ldif_uid);
754 fprintf(add_fd, "gidNumber: %d\n", gidNumber);
755 fprintf_attr(add_fd, "homeDirectory", "%s", homedir);
757 fprintf_attr(add_fd, "sambaHomePath", "%s", homepath);
759 fprintf_attr(add_fd, "sambaHomeDrive", "%s", homedrive);
761 fprintf_attr(add_fd, "sambaLogonScript", "%s", logonscript);
762 fprintf(add_fd, "loginShell: %s\n",
763 ((r->acct_flags & ACB_NORMAL) ?
764 "/bin/bash" : "/bin/false"));
765 fprintf(add_fd, "gecos: System User\n");
767 fprintf_attr(add_fd, "description", "%s", description);
768 fprintf(add_fd, "sambaSID: %s-%d\n", sid, rid);
769 fprintf(add_fd, "sambaPrimaryGroupSID: %s\n", sambaSID);
771 fprintf_attr(add_fd, "displayName", "%s", fullname);
773 fprintf_attr(add_fd, "sambaProfilePath", "%s", profilepath);
774 if (strcmp(nopasswd, hex_lm_passwd) != 0)
775 fprintf(add_fd, "sambaLMPassword: %s\n", hex_lm_passwd);
776 if (strcmp(nopasswd, hex_nt_passwd) != 0)
777 fprintf(add_fd, "sambaNTPassword: %s\n", hex_nt_passwd);
778 fprintf(add_fd, "sambaPwdLastSet: %d\n", (int)unix_time);
779 fprintf(add_fd, "sambaAcctFlags: %s\n", flags);
780 fprintf(add_fd, "\n");
787 /****************************************************************
788 ****************************************************************/
790 static NTSTATUS fetch_alias_info_to_ldif(TALLOC_CTX *mem_ctx,
791 struct netr_DELTA_ALIAS *r,
796 enum netr_SamDatabaseID database_id)
798 fstring aliasname, description;
799 uint32_t grouptype = 0, g_rid = 0;
800 char *group_attr = sstring_sub(lp_ldap_group_suffix(talloc_tos()), '=', ',');
802 /* Get the alias name */
803 fstrcpy(aliasname, r->alias_name.string);
805 /* Get the alias description */
806 fstrcpy(description, r->description.string);
808 /* Set up the group type */
809 switch (database_id) {
810 case SAM_DATABASE_DOMAIN:
813 case SAM_DATABASE_BUILTIN:
822 These groups are entered by populate_ldap_for_ldif
823 Note that populate creates a group called Relicators,
824 but NT returns a group called Replicator
826 if (strcmp(aliasname, "Domain Admins") == 0 ||
827 strcmp(aliasname, "Domain Users") == 0 ||
828 strcmp(aliasname, "Domain Guests") == 0 ||
829 strcmp(aliasname, "Domain Computers") == 0 ||
830 strcmp(aliasname, "Administrators") == 0 ||
831 strcmp(aliasname, "Print Operators") == 0 ||
832 strcmp(aliasname, "Backup Operators") == 0 ||
833 strcmp(aliasname, "Replicator") == 0) {
834 SAFE_FREE(group_attr);
837 /* Increment the gid for the new group */
841 /* Map the group rid and gid */
843 groupmap->gidNumber = ldif_gid;
844 groupmap->sambaSID = talloc_asprintf(mem_ctx, "%s-%d", sid, g_rid);
845 if (groupmap->sambaSID == NULL) {
846 SAFE_FREE(group_attr);
847 return NT_STATUS_NO_MEMORY;
850 /* Write the data to the temporary add ldif file */
851 fprintf(add_fd, "# %s, %s, %s\n", aliasname, group_attr,
853 fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", aliasname, group_attr,
855 fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP);
856 fprintf(add_fd, "objectClass: %s\n", LDAP_OBJ_GROUPMAP);
857 fprintf(add_fd, "cn: %s\n", aliasname);
858 fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
859 fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
860 fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
861 fprintf_attr(add_fd, "displayName", "%s", aliasname);
863 fprintf_attr(add_fd, "description", "%s", description);
864 fprintf(add_fd, "\n");
867 SAFE_FREE(group_attr);
872 /****************************************************************
873 ****************************************************************/
875 static NTSTATUS fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER *r,
878 ACCOUNTMAP *accountmap,
879 FILE *mod_fd, int alloced)
882 uint32_t group_rid = 0, rid = 0;
885 /* Get the dn for the group */
886 if (r->num_rids > 0) {
888 for (j=0; j<alloced; j++) {
889 if (groupmap[j].rid == group_rid) break;
892 DEBUG(1, ("Could not find rid %d in groupmap array\n",
894 return NT_STATUS_UNSUCCESSFUL;
896 snprintf(group_dn, sizeof(group_dn), "%s", groupmap[j].group_dn);
897 fprintf(mod_fd, "dn: %s\n", group_dn);
899 /* Get the cn for each member */
900 for (i=0; i < r->num_rids; i++) {
902 for (k=0; k<alloced; k++) {
903 if (accountmap[k].rid == rid) break;
906 DEBUG(1, ("Could not find rid %d in "
907 "accountmap array\n", rid));
908 return NT_STATUS_UNSUCCESSFUL;
910 fprintf(mod_fd, "memberUid: %s\n", accountmap[k].cn);
912 fprintf(mod_fd, "\n");
920 /****************************************************************
921 ****************************************************************/
923 static NTSTATUS ldif_init_context(TALLOC_CTX *mem_ctx,
924 enum netr_SamDatabaseID database_id,
925 const char *ldif_filename,
926 const char *domain_sid_str,
927 struct samsync_ldif_context **ctx)
929 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
930 struct samsync_ldif_context *r;
931 const char *add_template = "/tmp/add.ldif.XXXXXX";
932 const char *mod_template = "/tmp/mod.ldif.XXXXXX";
933 const char *builtin_sid = "S-1-5-32";
937 r = talloc_zero(mem_ctx, struct samsync_ldif_context);
938 NT_STATUS_HAVE_NO_MEMORY(r);
940 /* Get the ldap suffix */
941 r->suffix = lp_ldap_suffix(talloc_tos());
943 /* Get other smb.conf data */
944 if (!(lp_workgroup()) || !*(lp_workgroup())) {
945 DEBUG(0,("workgroup missing from smb.conf--exiting\n"));
949 /* Get the ldap suffix */
950 if (!r->suffix || !*r->suffix) {
951 DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
955 if (*ctx && (*ctx)->initialized) {
959 /* Ensure we have an output file */
961 r->ldif_file = fopen(ldif_filename, "a");
963 r->ldif_file = stdout;
967 fprintf(stderr, "Could not open %s\n", ldif_filename);
968 DEBUG(1, ("Could not open %s\n", ldif_filename));
969 status = NT_STATUS_UNSUCCESSFUL;
973 r->add_template = talloc_strdup(mem_ctx, add_template);
974 r->mod_template = talloc_strdup(mem_ctx, mod_template);
975 if (!r->add_template || !r->mod_template) {
976 status = NT_STATUS_NO_MEMORY;
980 r->add_name = talloc_strdup(mem_ctx, add_template);
981 r->module_name = talloc_strdup(mem_ctx, mod_template);
982 if (!r->add_name || !r->module_name) {
983 status = NT_STATUS_NO_MEMORY;
987 mask = umask(S_IRWXO | S_IRWXG);
988 fd = mkstemp(r->add_name);
991 DEBUG(1, ("Could not create %s\n", r->add_name));
992 status = NT_STATUS_UNSUCCESSFUL;
996 /* Open the add and mod ldif files */
997 r->add_file = fdopen(fd, "w");
998 if (r->add_file == NULL) {
999 DEBUG(1, ("Could not open %s\n", r->add_name));
1001 status = NT_STATUS_UNSUCCESSFUL;
1005 mask = umask(S_IRWXO | S_IRWXG);
1006 fd = mkstemp(r->module_name);
1009 DEBUG(1, ("Could not create %s\n", r->module_name));
1010 status = NT_STATUS_UNSUCCESSFUL;
1014 r->mod_file = fdopen(fd, "w");
1015 if (r->mod_file == NULL) {
1016 DEBUG(1, ("Could not open %s\n", r->module_name));
1018 status = NT_STATUS_UNSUCCESSFUL;
1022 /* Allocate initial memory for groupmap and accountmap arrays */
1023 r->groupmap = talloc_zero_array(mem_ctx, GROUPMAP, 8);
1024 r->accountmap = talloc_zero_array(mem_ctx, ACCOUNTMAP, 8);
1025 if (r->groupmap == NULL || r->accountmap == NULL) {
1026 DEBUG(1,("GROUPMAP talloc failed\n"));
1027 status = NT_STATUS_NO_MEMORY;
1031 /* Remember how many we malloced */
1034 /* Initial database population */
1035 if (database_id == SAM_DATABASE_DOMAIN) {
1037 status = populate_ldap_for_ldif(domain_sid_str,
1041 if (!NT_STATUS_IS_OK(status)) {
1045 status = map_populate_groups(mem_ctx,
1051 if (!NT_STATUS_IS_OK(status)) {
1056 r->initialized = true;
1060 return NT_STATUS_OK;
1066 /****************************************************************
1067 ****************************************************************/
1069 static void ldif_free_context(struct samsync_ldif_context *r)
1075 /* Close and delete the ldif files */
1077 fclose(r->add_file);
1080 if ((r->add_name != NULL) &&
1081 strcmp(r->add_name, r->add_template) && (unlink(r->add_name))) {
1082 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
1083 r->add_name, strerror(errno)));
1087 fclose(r->mod_file);
1090 if ((r->module_name != NULL) &&
1091 strcmp(r->module_name, r->mod_template) && (unlink(r->module_name))) {
1092 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
1093 r->module_name, strerror(errno)));
1096 if (r->ldif_file && (r->ldif_file != stdout)) {
1097 fclose(r->ldif_file);
1103 /****************************************************************
1104 ****************************************************************/
1106 static void ldif_write_output(enum netr_SamDatabaseID database_id,
1107 struct samsync_ldif_context *l)
1109 /* Write ldif data to the user's file */
1110 if (database_id == SAM_DATABASE_DOMAIN) {
1111 fprintf(l->ldif_file,
1112 "# SAM_DATABASE_DOMAIN: ADD ENTITIES\n");
1113 fprintf(l->ldif_file,
1114 "# =================================\n\n");
1115 fflush(l->ldif_file);
1116 } else if (database_id == SAM_DATABASE_BUILTIN) {
1117 fprintf(l->ldif_file,
1118 "# SAM_DATABASE_BUILTIN: ADD ENTITIES\n");
1119 fprintf(l->ldif_file,
1120 "# ==================================\n\n");
1121 fflush(l->ldif_file);
1123 fseek(l->add_file, 0, SEEK_SET);
1124 transfer_file(fileno(l->add_file), fileno(l->ldif_file), (size_t) -1);
1126 if (database_id == SAM_DATABASE_DOMAIN) {
1127 fprintf(l->ldif_file,
1128 "# SAM_DATABASE_DOMAIN: MODIFY ENTITIES\n");
1129 fprintf(l->ldif_file,
1130 "# ====================================\n\n");
1131 fflush(l->ldif_file);
1132 } else if (database_id == SAM_DATABASE_BUILTIN) {
1133 fprintf(l->ldif_file,
1134 "# SAM_DATABASE_BUILTIN: MODIFY ENTITIES\n");
1135 fprintf(l->ldif_file,
1136 "# =====================================\n\n");
1137 fflush(l->ldif_file);
1139 fseek(l->mod_file, 0, SEEK_SET);
1140 transfer_file(fileno(l->mod_file), fileno(l->ldif_file), (size_t) -1);
1143 /****************************************************************
1144 ****************************************************************/
1146 static NTSTATUS fetch_sam_entry_ldif(TALLOC_CTX *mem_ctx,
1147 enum netr_SamDatabaseID database_id,
1148 struct netr_DELTA_ENUM *r,
1149 struct samsync_context *ctx,
1150 uint32_t *a_index_p,
1151 uint32_t *g_index_p)
1153 union netr_DELTA_UNION u = r->delta_union;
1154 union netr_DELTA_ID_UNION id = r->delta_id_union;
1155 struct samsync_ldif_context *l =
1156 talloc_get_type_abort(ctx->private_data, struct samsync_ldif_context);
1158 switch (r->delta_type) {
1159 case NETR_DELTA_DOMAIN:
1162 case NETR_DELTA_GROUP:
1163 fetch_group_info_to_ldif(mem_ctx,
1165 &l->groupmap[*g_index_p],
1167 ctx->domain_sid_str,
1172 case NETR_DELTA_USER:
1173 fetch_account_info_to_ldif(mem_ctx,
1176 &l->accountmap[*a_index_p],
1178 ctx->domain_sid_str,
1184 case NETR_DELTA_ALIAS:
1185 fetch_alias_info_to_ldif(mem_ctx,
1187 &l->groupmap[*g_index_p],
1189 ctx->domain_sid_str,
1195 case NETR_DELTA_GROUP_MEMBER:
1196 fetch_groupmem_info_to_ldif(u.group_member,
1204 case NETR_DELTA_ALIAS_MEMBER:
1205 case NETR_DELTA_POLICY:
1206 case NETR_DELTA_ACCOUNT:
1207 case NETR_DELTA_TRUSTED_DOMAIN:
1208 case NETR_DELTA_SECRET:
1209 case NETR_DELTA_RENAME_GROUP:
1210 case NETR_DELTA_RENAME_USER:
1211 case NETR_DELTA_RENAME_ALIAS:
1212 case NETR_DELTA_DELETE_GROUP:
1213 case NETR_DELTA_DELETE_USER:
1214 case NETR_DELTA_MODIFY_COUNT:
1217 } /* end of switch */
1219 return NT_STATUS_OK;
1222 /****************************************************************
1223 ****************************************************************/
1225 static NTSTATUS ldif_realloc_maps(TALLOC_CTX *mem_ctx,
1226 struct samsync_ldif_context *l,
1227 uint32_t num_entries)
1229 /* Re-allocate memory for groupmap and accountmap arrays */
1230 l->groupmap = talloc_realloc(mem_ctx,
1233 num_entries + l->num_alloced);
1235 l->accountmap = talloc_realloc(mem_ctx,
1238 num_entries + l->num_alloced);
1240 if (l->groupmap == NULL || l->accountmap == NULL) {
1241 DEBUG(1,("GROUPMAP talloc failed\n"));
1242 return NT_STATUS_NO_MEMORY;
1245 /* Initialize the new records */
1246 memset(&(l->groupmap[l->num_alloced]), 0,
1247 sizeof(GROUPMAP) * num_entries);
1248 memset(&(l->accountmap[l->num_alloced]), 0,
1249 sizeof(ACCOUNTMAP) * num_entries);
1251 /* Remember how many we alloced this time */
1252 l->num_alloced += num_entries;
1254 return NT_STATUS_OK;
1257 /****************************************************************
1258 ****************************************************************/
1260 static NTSTATUS init_ldif(TALLOC_CTX *mem_ctx,
1261 struct samsync_context *ctx,
1262 enum netr_SamDatabaseID database_id,
1263 uint64_t *sequence_num)
1266 struct samsync_ldif_context *ldif_ctx =
1267 (struct samsync_ldif_context *)ctx->private_data;
1269 status = ldif_init_context(mem_ctx,
1271 ctx->output_filename,
1272 ctx->domain_sid_str,
1274 if (!NT_STATUS_IS_OK(status)) {
1278 ctx->private_data = ldif_ctx;
1280 return NT_STATUS_OK;
1283 /****************************************************************
1284 ****************************************************************/
1286 static NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
1287 enum netr_SamDatabaseID database_id,
1288 struct netr_DELTA_ENUM_ARRAY *r,
1289 uint64_t *sequence_num,
1290 struct samsync_context *ctx)
1294 struct samsync_ldif_context *ldif_ctx =
1295 (struct samsync_ldif_context *)ctx->private_data;
1297 status = ldif_realloc_maps(mem_ctx, ldif_ctx, r->num_deltas);
1298 if (!NT_STATUS_IS_OK(status)) {
1302 for (i = 0; i < r->num_deltas; i++) {
1303 status = fetch_sam_entry_ldif(mem_ctx, database_id,
1304 &r->delta_enum[i], ctx,
1305 &a_index, &g_index);
1306 if (!NT_STATUS_IS_OK(status)) {
1311 return NT_STATUS_OK;
1314 ldif_free_context(ldif_ctx);
1315 ctx->private_data = NULL;
1320 /****************************************************************
1321 ****************************************************************/
1323 static NTSTATUS close_ldif(TALLOC_CTX *mem_ctx,
1324 struct samsync_context *ctx,
1325 enum netr_SamDatabaseID database_id,
1326 uint64_t sequence_num)
1328 struct samsync_ldif_context *ldif_ctx =
1329 (struct samsync_ldif_context *)ctx->private_data;
1331 /* This was the last query */
1332 ldif_write_output(database_id, ldif_ctx);
1333 if (ldif_ctx->ldif_file != stdout) {
1334 ctx->result_message = talloc_asprintf(ctx,
1335 "Vampired %d accounts and %d groups to %s",
1336 a_index, g_index, ctx->output_filename);
1339 ldif_free_context(ldif_ctx);
1340 ctx->private_data = NULL;
1342 return NT_STATUS_OK;
1345 #else /* HAVE_LDAP */
1347 static NTSTATUS init_ldif(TALLOC_CTX *mem_ctx,
1348 struct samsync_context *ctx,
1349 enum netr_SamDatabaseID database_id,
1350 uint64_t *sequence_num)
1352 return NT_STATUS_NOT_SUPPORTED;
1355 static NTSTATUS fetch_sam_entries_ldif(TALLOC_CTX *mem_ctx,
1356 enum netr_SamDatabaseID database_id,
1357 struct netr_DELTA_ENUM_ARRAY *r,
1358 uint64_t *sequence_num,
1359 struct samsync_context *ctx)
1361 return NT_STATUS_NOT_SUPPORTED;
1364 static NTSTATUS close_ldif(TALLOC_CTX *mem_ctx,
1365 struct samsync_context *ctx,
1366 enum netr_SamDatabaseID database_id,
1367 uint64_t sequence_num)
1369 return NT_STATUS_NOT_SUPPORTED;
1374 const struct samsync_ops libnet_samsync_ldif_ops = {
1375 .startup = init_ldif,
1376 .process_objects = fetch_sam_entries_ldif,
1377 .finish = close_ldif,