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 "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
{
42 typedef struct _accountmap
{
47 struct samsync_ldif_context
{
49 ACCOUNTMAP
*accountmap
;
51 const char *add_template
;
52 const char *mod_template
;
62 /****************************************************************
63 ****************************************************************/
65 static NTSTATUS
populate_ldap_for_ldif(const char *sid
,
67 const char *builtin_sid
,
70 const char *user_suffix
, *group_suffix
, *machine_suffix
, *idmap_suffix
;
71 char *user_attr
=NULL
, *group_attr
=NULL
;
75 /* Get the suffix attribute */
76 suffix_attr
= sstring_sub(suffix
, '=', ',');
77 if (suffix_attr
== NULL
) {
79 suffix_attr
= (char*)SMB_MALLOC(len
+1);
80 memcpy(suffix_attr
, suffix
, len
);
81 suffix_attr
[len
] = '\0';
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");
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");
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");
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");
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
;
164 strcmp(idmap_suffix
, user_suffix
) &&
165 strcmp(idmap_suffix
, suffix
)) {
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
);
173 fprintf(add_fd
, "\n");
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(),
181 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_DOMINFO
);
182 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_IDPOOL
);
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");
190 /* Write the Domain Admins entity */
191 fprintf(add_fd
, "# Domain Admins, %s, %s\n", group_attr
,
193 fprintf(add_fd
, "dn: cn=Domain Admins,ou=%s,%s\n", group_attr
,
195 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
196 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
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");
207 /* Write the Domain Users entity */
208 fprintf(add_fd
, "# Domain Users, %s, %s\n", group_attr
,
210 fprintf(add_fd
, "dn: cn=Domain Users,ou=%s,%s\n", group_attr
,
212 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
213 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
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");
223 /* Write the Domain Guests entity */
224 fprintf(add_fd
, "# Domain Guests, %s, %s\n", group_attr
,
226 fprintf(add_fd
, "dn: cn=Domain Guests,ou=%s,%s\n", group_attr
,
228 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
229 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
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");
239 /* Write the Domain Computers entity */
240 fprintf(add_fd
, "# Domain Computers, %s, %s\n", group_attr
,
242 fprintf(add_fd
, "dn: cn=Domain Computers,ou=%s,%s\n",
244 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
245 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
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");
255 /* Write the Admininistrators Groups entity */
256 fprintf(add_fd
, "# Administrators, %s, %s\n", group_attr
,
258 fprintf(add_fd
, "dn: cn=Administrators,ou=%s,%s\n", group_attr
,
260 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
261 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
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
,
273 fprintf(add_fd
, "dn: cn=Print Operators,ou=%s,%s\n",
275 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
276 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
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");
286 /* Write the Backup Operators entity */
287 fprintf(add_fd
, "# Backup Operators, %s, %s\n", group_attr
,
289 fprintf(add_fd
, "dn: cn=Backup Operators,ou=%s,%s\n",
291 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
292 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
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");
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
,
306 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
307 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
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");
317 /* Deallocate memory, and return */
318 SAFE_FREE(suffix_attr
);
319 SAFE_FREE(user_attr
);
320 SAFE_FREE(group_attr
);
324 /****************************************************************
325 ****************************************************************/
327 static NTSTATUS
map_populate_groups(TALLOC_CTX
*mem_ctx
,
329 ACCOUNTMAP
*accountmap
,
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
);
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
, ...)
447 char *value
, *p
, *base64
;
448 DATA_BLOB base64_blob
;
449 bool do_base64
= false;
453 value
= talloc_vasprintf(NULL
, fmt
, ap
);
456 SMB_ASSERT(value
!= NULL
);
458 for (p
=value
; *p
; p
++) {
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.
473 only_whitespace
= false;
477 if (only_whitespace
) {
483 res
= fprintf(add_fd
, "%s: %s\n", attr_name
, value
);
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
);
499 /****************************************************************
500 ****************************************************************/
502 static NTSTATUS
fetch_group_info_to_ldif(TALLOC_CTX
*mem_ctx
,
503 struct netr_DELTA_GROUP
*r
,
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) */
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
);
528 /* Increment the gid for the new group */
532 /* Map the group rid, gid, and dn */
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
,
545 fprintf_attr(add_fd
, "dn", "cn=%s,ou=%s,%s", groupname
, group_attr
,
547 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
548 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
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");
557 SAFE_FREE(group_attr
);
562 /****************************************************************
563 ****************************************************************/
565 static NTSTATUS
fetch_account_info_to_ldif(TALLOC_CTX
*mem_ctx
,
566 struct netr_DELTA_USER
*r
,
568 ACCOUNTMAP
*accountmap
,
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
;
580 const char* nopasswd
= "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
581 static uchar zero_buf
[16];
582 uint32 rid
= 0, group_rid
= 0, gidNumber
= 0;
586 /* Get the username */
587 fstrcpy(username
, r
->account_name
.string
);
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
);
601 snprintf(homedir
, sizeof(homedir
), "/home/%s", username
);
603 snprintf(homedir
, sizeof(homedir
), "/nobodyshomedir");
605 ou
= lp_ldap_user_suffix();
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
);
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
);
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 */
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;
653 DEBUG(1, ("Could not find rid %d in groupmap array\n",
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
,
671 fprintf(add_fd
, "ObjectClass: top\n");
672 fprintf(add_fd
, "objectClass: inetOrgPerson\n");
673 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXACCOUNT
);
674 fprintf(add_fd
, "objectClass: shadowAccount\n");
675 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_SAMBASAMACCOUNT
);
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
);
683 fprintf_attr(add_fd
, "sambaHomePath", "%s", homepath
);
685 fprintf_attr(add_fd
, "sambaHomeDrive", "%s", homedrive
);
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");
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
);
697 fprintf_attr(add_fd
, "displayName", "%s", fullname
);
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");
713 /****************************************************************
714 ****************************************************************/
716 static NTSTATUS
fetch_alias_info_to_ldif(TALLOC_CTX
*mem_ctx
,
717 struct netr_DELTA_ALIAS
*r
,
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
:
739 case SAM_DATABASE_BUILTIN
:
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
);
763 /* Increment the gid for the new group */
767 /* Map the group rid and gid */
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
,
776 fprintf_attr(add_fd
, "dn", "cn=%s,ou=%s,%s", aliasname
, group_attr
,
778 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
779 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
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
);
786 fprintf_attr(add_fd
, "description", "%s", description
);
787 fprintf(add_fd
, "\n");
790 SAFE_FREE(group_attr
);
795 /****************************************************************
796 ****************************************************************/
798 static NTSTATUS
fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER
*r
,
801 ACCOUNTMAP
*accountmap
,
802 FILE *mod_fd
, int alloced
)
805 uint32 group_rid
= 0, rid
= 0;
808 /* Get the dn for the group */
809 if (r
->num_rids
> 0) {
811 for (j
=0; j
<alloced
; j
++) {
812 if (groupmap
[j
].rid
== group_rid
) break;
815 DEBUG(1, ("Could not find rid %d in groupmap array\n",
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
++) {
825 for (k
=0; k
<alloced
; k
++) {
826 if (accountmap
[k
].rid
== rid
) break;
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");
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"));
864 /* Get the ldap suffix */
865 if (!(lp_ldap_suffix()) || !*(lp_ldap_suffix())) {
866 DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
870 if (*ctx
&& (*ctx
)->initialized
) {
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 */
882 r
->ldif_file
= fopen(ldif_filename
, "a");
884 r
->ldif_file
= stdout
;
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
;
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
;
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
;
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
;
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
;
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
;
929 /* Remember how many we malloced */
932 /* Initial database population */
933 if (database_id
== SAM_DATABASE_DOMAIN
) {
935 status
= populate_ldap_for_ldif(domain_sid_str
,
939 if (!NT_STATUS_IS_OK(status
)) {
943 status
= map_populate_groups(mem_ctx
,
949 if (!NT_STATUS_IS_OK(status
)) {
954 r
->initialized
= true;
964 /****************************************************************
965 ****************************************************************/
967 static void ldif_free_context(struct samsync_ldif_context
*r
)
973 /* Close and delete the ldif files */
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
)));
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
);
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
,
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
:
1060 case NETR_DELTA_GROUP
:
1061 fetch_group_info_to_ldif(mem_ctx
,
1063 &l
->groupmap
[*g_index
],
1065 ctx
->domain_sid_str
,
1070 case NETR_DELTA_USER
:
1071 fetch_account_info_to_ldif(mem_ctx
,
1074 &l
->accountmap
[*a_index
],
1076 ctx
->domain_sid_str
,
1082 case NETR_DELTA_ALIAS
:
1083 fetch_alias_info_to_ldif(mem_ctx
,
1085 &l
->groupmap
[*g_index
],
1087 ctx
->domain_sid_str
,
1093 case NETR_DELTA_GROUP_MEMBER
:
1094 fetch_groupmem_info_to_ldif(u
.group_member
,
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
:
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
,
1131 num_entries
+ l
->num_alloced
);
1133 l
->accountmap
= TALLOC_REALLOC_ARRAY(mem_ctx
,
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
,
1162 struct samsync_context
*ctx
)
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
,
1172 ctx
->output_filename
,
1173 ctx
->domain_sid_str
,
1175 if (!NT_STATUS_IS_OK(status
)) {
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
)) {
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
)) {
1195 /* This was the 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
;
1210 ldif_free_context(ldif_ctx
);
1211 ctx
->private_data
= NULL
;