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 #include "transfer_file.h"
34 /* uid's and gid's for writing deltas to ldif */
35 static uint32 ldif_gid
= 999;
36 static uint32 ldif_uid
= 999;
39 static uint32_t g_index
= 0;
40 static uint32_t a_index
= 0;
42 /* Structure for mapping accounts to groups */
43 /* Array element is the group rid */
44 typedef struct _groupmap
{
51 typedef struct _accountmap
{
56 struct samsync_ldif_context
{
58 ACCOUNTMAP
*accountmap
;
60 const char *add_template
;
61 const char *mod_template
;
71 /****************************************************************
72 ****************************************************************/
74 static NTSTATUS
populate_ldap_for_ldif(const char *sid
,
76 const char *builtin_sid
,
79 const char *user_suffix
, *group_suffix
, *machine_suffix
, *idmap_suffix
;
80 char *user_attr
=NULL
, *group_attr
=NULL
;
84 /* Get the suffix attribute */
85 suffix_attr
= sstring_sub(suffix
, '=', ',');
86 if (suffix_attr
== NULL
) {
88 suffix_attr
= (char*)SMB_MALLOC(len
+1);
90 return NT_STATUS_NO_MEMORY
;
92 memcpy(suffix_attr
, suffix
, len
);
93 suffix_attr
[len
] = '\0';
97 fprintf(add_fd
, "# %s\n", suffix
);
98 fprintf(add_fd
, "dn: %s\n", suffix
);
99 fprintf(add_fd
, "objectClass: dcObject\n");
100 fprintf(add_fd
, "objectClass: organization\n");
101 fprintf(add_fd
, "o: %s\n", suffix_attr
);
102 fprintf(add_fd
, "dc: %s\n", suffix_attr
);
103 fprintf(add_fd
, "\n");
106 user_suffix
= lp_ldap_user_suffix();
107 if (user_suffix
== NULL
) {
108 SAFE_FREE(suffix_attr
);
109 return NT_STATUS_NO_MEMORY
;
111 /* If it exists and is distinct from other containers,
112 Write the Users entity */
113 if (*user_suffix
&& strcmp(user_suffix
, suffix
)) {
114 user_attr
= sstring_sub(lp_ldap_user_suffix(), '=', ',');
115 fprintf(add_fd
, "# %s\n", user_suffix
);
116 fprintf(add_fd
, "dn: %s\n", user_suffix
);
117 fprintf(add_fd
, "objectClass: organizationalUnit\n");
118 fprintf(add_fd
, "ou: %s\n", user_attr
);
119 fprintf(add_fd
, "\n");
124 group_suffix
= lp_ldap_group_suffix();
125 if (group_suffix
== NULL
) {
126 SAFE_FREE(suffix_attr
);
127 SAFE_FREE(user_attr
);
128 return NT_STATUS_NO_MEMORY
;
130 /* If it exists and is distinct from other containers,
131 Write the Groups entity */
132 if (*group_suffix
&& strcmp(group_suffix
, suffix
)) {
133 group_attr
= sstring_sub(lp_ldap_group_suffix(), '=', ',');
134 fprintf(add_fd
, "# %s\n", group_suffix
);
135 fprintf(add_fd
, "dn: %s\n", group_suffix
);
136 fprintf(add_fd
, "objectClass: organizationalUnit\n");
137 fprintf(add_fd
, "ou: %s\n", group_attr
);
138 fprintf(add_fd
, "\n");
142 /* If it exists and is distinct from other containers,
143 Write the Computers entity */
144 machine_suffix
= lp_ldap_machine_suffix();
145 if (machine_suffix
== NULL
) {
146 SAFE_FREE(suffix_attr
);
147 SAFE_FREE(user_attr
);
148 SAFE_FREE(group_attr
);
149 return NT_STATUS_NO_MEMORY
;
151 if (*machine_suffix
&& strcmp(machine_suffix
, user_suffix
) &&
152 strcmp(machine_suffix
, suffix
)) {
153 char *machine_ou
= NULL
;
154 fprintf(add_fd
, "# %s\n", machine_suffix
);
155 fprintf(add_fd
, "dn: %s\n", machine_suffix
);
156 fprintf(add_fd
, "objectClass: organizationalUnit\n");
157 /* this isn't totally correct as it assumes that
158 there _must_ be an ou. just fixing memleak now. jmcd */
159 machine_ou
= sstring_sub(lp_ldap_machine_suffix(), '=', ',');
160 fprintf(add_fd
, "ou: %s\n", machine_ou
);
161 SAFE_FREE(machine_ou
);
162 fprintf(add_fd
, "\n");
166 /* If it exists and is distinct from other containers,
167 Write the IdMap entity */
168 idmap_suffix
= lp_ldap_idmap_suffix();
169 if (idmap_suffix
== NULL
) {
170 SAFE_FREE(suffix_attr
);
171 SAFE_FREE(user_attr
);
172 SAFE_FREE(group_attr
);
173 return NT_STATUS_NO_MEMORY
;
176 strcmp(idmap_suffix
, user_suffix
) &&
177 strcmp(idmap_suffix
, suffix
)) {
179 fprintf(add_fd
, "# %s\n", idmap_suffix
);
180 fprintf(add_fd
, "dn: %s\n", idmap_suffix
);
181 fprintf(add_fd
, "ObjectClass: organizationalUnit\n");
182 s
= sstring_sub(lp_ldap_idmap_suffix(), '=', ',');
183 fprintf(add_fd
, "ou: %s\n", s
);
185 fprintf(add_fd
, "\n");
189 /* Write the domain entity */
190 fprintf(add_fd
, "# %s, %s\n", lp_workgroup(), suffix
);
191 fprintf(add_fd
, "dn: sambaDomainName=%s,%s\n", lp_workgroup(),
193 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_DOMINFO
);
194 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_IDPOOL
);
195 fprintf(add_fd
, "sambaDomainName: %s\n", lp_workgroup());
196 fprintf(add_fd
, "sambaSID: %s\n", sid
);
197 fprintf(add_fd
, "uidNumber: %d\n", ++ldif_uid
);
198 fprintf(add_fd
, "gidNumber: %d\n", ++ldif_gid
);
199 fprintf(add_fd
, "\n");
202 /* Write the Domain Admins entity */
203 fprintf(add_fd
, "# Domain Admins, %s, %s\n", group_attr
,
205 fprintf(add_fd
, "dn: cn=Domain Admins,ou=%s,%s\n", group_attr
,
207 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
208 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
209 fprintf(add_fd
, "cn: Domain Admins\n");
210 fprintf(add_fd
, "memberUid: Administrator\n");
211 fprintf(add_fd
, "description: Netbios Domain Administrators\n");
212 fprintf(add_fd
, "gidNumber: 512\n");
213 fprintf(add_fd
, "sambaSID: %s-512\n", sid
);
214 fprintf(add_fd
, "sambaGroupType: 2\n");
215 fprintf(add_fd
, "displayName: Domain Admins\n");
216 fprintf(add_fd
, "\n");
219 /* Write the Domain Users entity */
220 fprintf(add_fd
, "# Domain Users, %s, %s\n", group_attr
,
222 fprintf(add_fd
, "dn: cn=Domain Users,ou=%s,%s\n", group_attr
,
224 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
225 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
226 fprintf(add_fd
, "cn: Domain Users\n");
227 fprintf(add_fd
, "description: Netbios Domain Users\n");
228 fprintf(add_fd
, "gidNumber: 513\n");
229 fprintf(add_fd
, "sambaSID: %s-513\n", sid
);
230 fprintf(add_fd
, "sambaGroupType: 2\n");
231 fprintf(add_fd
, "displayName: Domain Users\n");
232 fprintf(add_fd
, "\n");
235 /* Write the Domain Guests entity */
236 fprintf(add_fd
, "# Domain Guests, %s, %s\n", group_attr
,
238 fprintf(add_fd
, "dn: cn=Domain Guests,ou=%s,%s\n", group_attr
,
240 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
241 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
242 fprintf(add_fd
, "cn: Domain Guests\n");
243 fprintf(add_fd
, "description: Netbios Domain Guests\n");
244 fprintf(add_fd
, "gidNumber: 514\n");
245 fprintf(add_fd
, "sambaSID: %s-514\n", sid
);
246 fprintf(add_fd
, "sambaGroupType: 2\n");
247 fprintf(add_fd
, "displayName: Domain Guests\n");
248 fprintf(add_fd
, "\n");
251 /* Write the Domain Computers entity */
252 fprintf(add_fd
, "# Domain Computers, %s, %s\n", group_attr
,
254 fprintf(add_fd
, "dn: cn=Domain Computers,ou=%s,%s\n",
256 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
257 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
258 fprintf(add_fd
, "gidNumber: 515\n");
259 fprintf(add_fd
, "cn: Domain Computers\n");
260 fprintf(add_fd
, "description: Netbios Domain Computers accounts\n");
261 fprintf(add_fd
, "sambaSID: %s-515\n", sid
);
262 fprintf(add_fd
, "sambaGroupType: 2\n");
263 fprintf(add_fd
, "displayName: Domain Computers\n");
264 fprintf(add_fd
, "\n");
267 /* Write the Admininistrators Groups entity */
268 fprintf(add_fd
, "# Administrators, %s, %s\n", group_attr
,
270 fprintf(add_fd
, "dn: cn=Administrators,ou=%s,%s\n", group_attr
,
272 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
273 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
274 fprintf(add_fd
, "gidNumber: 544\n");
275 fprintf(add_fd
, "cn: Administrators\n");
276 fprintf(add_fd
, "description: Netbios Domain Members can fully administer the computer/sambaDomainName\n");
277 fprintf(add_fd
, "sambaSID: %s-544\n", builtin_sid
);
278 fprintf(add_fd
, "sambaGroupType: 5\n");
279 fprintf(add_fd
, "displayName: Administrators\n");
280 fprintf(add_fd
, "\n");
282 /* Write the Print Operator entity */
283 fprintf(add_fd
, "# Print Operators, %s, %s\n", group_attr
,
285 fprintf(add_fd
, "dn: cn=Print Operators,ou=%s,%s\n",
287 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
288 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
289 fprintf(add_fd
, "gidNumber: 550\n");
290 fprintf(add_fd
, "cn: Print Operators\n");
291 fprintf(add_fd
, "description: Netbios Domain Print Operators\n");
292 fprintf(add_fd
, "sambaSID: %s-550\n", builtin_sid
);
293 fprintf(add_fd
, "sambaGroupType: 5\n");
294 fprintf(add_fd
, "displayName: Print Operators\n");
295 fprintf(add_fd
, "\n");
298 /* Write the Backup Operators entity */
299 fprintf(add_fd
, "# Backup Operators, %s, %s\n", group_attr
,
301 fprintf(add_fd
, "dn: cn=Backup Operators,ou=%s,%s\n",
303 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
304 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
305 fprintf(add_fd
, "gidNumber: 551\n");
306 fprintf(add_fd
, "cn: Backup Operators\n");
307 fprintf(add_fd
, "description: Netbios Domain Members can bypass file security to back up files\n");
308 fprintf(add_fd
, "sambaSID: %s-551\n", builtin_sid
);
309 fprintf(add_fd
, "sambaGroupType: 5\n");
310 fprintf(add_fd
, "displayName: Backup Operators\n");
311 fprintf(add_fd
, "\n");
314 /* Write the Replicators entity */
315 fprintf(add_fd
, "# Replicators, %s, %s\n", group_attr
, suffix
);
316 fprintf(add_fd
, "dn: cn=Replicators,ou=%s,%s\n", group_attr
,
318 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
319 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
320 fprintf(add_fd
, "gidNumber: 552\n");
321 fprintf(add_fd
, "cn: Replicators\n");
322 fprintf(add_fd
, "description: Netbios Domain Supports file replication in a sambaDomainName\n");
323 fprintf(add_fd
, "sambaSID: %s-552\n", builtin_sid
);
324 fprintf(add_fd
, "sambaGroupType: 5\n");
325 fprintf(add_fd
, "displayName: Replicators\n");
326 fprintf(add_fd
, "\n");
329 /* Deallocate memory, and return */
330 SAFE_FREE(suffix_attr
);
331 SAFE_FREE(user_attr
);
332 SAFE_FREE(group_attr
);
336 /****************************************************************
337 ****************************************************************/
339 static NTSTATUS
map_populate_groups(TALLOC_CTX
*mem_ctx
,
341 ACCOUNTMAP
*accountmap
,
344 const char *builtin_sid
)
346 char *group_attr
= sstring_sub(lp_ldap_group_suffix(), '=', ',');
348 /* Map the groups created by populate_ldap_for_ldif */
349 groupmap
[0].rid
= 512;
350 groupmap
[0].gidNumber
= 512;
351 groupmap
[0].sambaSID
= talloc_asprintf(mem_ctx
, "%s-512", sid
);
352 groupmap
[0].group_dn
= talloc_asprintf(mem_ctx
,
353 "cn=Domain Admins,ou=%s,%s", group_attr
, suffix
);
354 if (groupmap
[0].sambaSID
== NULL
|| groupmap
[0].group_dn
== NULL
) {
358 accountmap
[0].rid
= 512;
359 accountmap
[0].cn
= talloc_strdup(mem_ctx
, "Domain Admins");
360 if (accountmap
[0].cn
== NULL
) {
364 groupmap
[1].rid
= 513;
365 groupmap
[1].gidNumber
= 513;
366 groupmap
[1].sambaSID
= talloc_asprintf(mem_ctx
, "%s-513", sid
);
367 groupmap
[1].group_dn
= talloc_asprintf(mem_ctx
,
368 "cn=Domain Users,ou=%s,%s", group_attr
, suffix
);
369 if (groupmap
[1].sambaSID
== NULL
|| groupmap
[1].group_dn
== NULL
) {
373 accountmap
[1].rid
= 513;
374 accountmap
[1].cn
= talloc_strdup(mem_ctx
, "Domain Users");
375 if (accountmap
[1].cn
== NULL
) {
379 groupmap
[2].rid
= 514;
380 groupmap
[2].gidNumber
= 514;
381 groupmap
[2].sambaSID
= talloc_asprintf(mem_ctx
, "%s-514", sid
);
382 groupmap
[2].group_dn
= talloc_asprintf(mem_ctx
,
383 "cn=Domain Guests,ou=%s,%s", group_attr
, suffix
);
384 if (groupmap
[2].sambaSID
== NULL
|| groupmap
[2].group_dn
== NULL
) {
388 accountmap
[2].rid
= 514;
389 accountmap
[2].cn
= talloc_strdup(mem_ctx
, "Domain Guests");
390 if (accountmap
[2].cn
== NULL
) {
394 groupmap
[3].rid
= 515;
395 groupmap
[3].gidNumber
= 515;
396 groupmap
[3].sambaSID
= talloc_asprintf(mem_ctx
, "%s-515", sid
);
397 groupmap
[3].group_dn
= talloc_asprintf(mem_ctx
,
398 "cn=Domain Computers,ou=%s,%s", group_attr
, suffix
);
399 if (groupmap
[3].sambaSID
== NULL
|| groupmap
[3].group_dn
== NULL
) {
403 accountmap
[3].rid
= 515;
404 accountmap
[3].cn
= talloc_strdup(mem_ctx
, "Domain Computers");
405 if (accountmap
[3].cn
== NULL
) {
409 groupmap
[4].rid
= 544;
410 groupmap
[4].gidNumber
= 544;
411 groupmap
[4].sambaSID
= talloc_asprintf(mem_ctx
, "%s-544", builtin_sid
);
412 groupmap
[4].group_dn
= talloc_asprintf(mem_ctx
,
413 "cn=Administrators,ou=%s,%s", group_attr
, suffix
);
414 if (groupmap
[4].sambaSID
== NULL
|| groupmap
[4].group_dn
== NULL
) {
418 accountmap
[4].rid
= 515;
419 accountmap
[4].cn
= talloc_strdup(mem_ctx
, "Administrators");
420 if (accountmap
[4].cn
== NULL
) {
424 groupmap
[5].rid
= 550;
425 groupmap
[5].gidNumber
= 550;
426 groupmap
[5].sambaSID
= talloc_asprintf(mem_ctx
, "%s-550", builtin_sid
);
427 groupmap
[5].group_dn
= talloc_asprintf(mem_ctx
,
428 "cn=Print Operators,ou=%s,%s", group_attr
, suffix
);
429 if (groupmap
[5].sambaSID
== NULL
|| groupmap
[5].group_dn
== NULL
) {
433 accountmap
[5].rid
= 550;
434 accountmap
[5].cn
= talloc_strdup(mem_ctx
, "Print Operators");
435 if (accountmap
[5].cn
== NULL
) {
439 groupmap
[6].rid
= 551;
440 groupmap
[6].gidNumber
= 551;
441 groupmap
[6].sambaSID
= talloc_asprintf(mem_ctx
, "%s-551", builtin_sid
);
442 groupmap
[6].group_dn
= talloc_asprintf(mem_ctx
,
443 "cn=Backup Operators,ou=%s,%s", group_attr
, suffix
);
444 if (groupmap
[6].sambaSID
== NULL
|| groupmap
[6].group_dn
== NULL
) {
448 accountmap
[6].rid
= 551;
449 accountmap
[6].cn
= talloc_strdup(mem_ctx
, "Backup Operators");
450 if (accountmap
[6].cn
== NULL
) {
454 groupmap
[7].rid
= 552;
455 groupmap
[7].gidNumber
= 552;
456 groupmap
[7].sambaSID
= talloc_asprintf(mem_ctx
, "%s-552", builtin_sid
);
457 groupmap
[7].group_dn
= talloc_asprintf(mem_ctx
,
458 "cn=Replicators,ou=%s,%s", group_attr
, suffix
);
459 if (groupmap
[7].sambaSID
== NULL
|| groupmap
[7].group_dn
== NULL
) {
463 accountmap
[7].rid
= 551;
464 accountmap
[7].cn
= talloc_strdup(mem_ctx
, "Replicators");
465 if (accountmap
[7].cn
== NULL
) {
469 SAFE_FREE(group_attr
);
475 SAFE_FREE(group_attr
);
476 return NT_STATUS_NO_MEMORY
;
480 * This is a crap routine, but I think it's the quickest way to solve the
481 * UTF8->base64 problem.
484 static int fprintf_attr(FILE *add_fd
, const char *attr_name
,
485 const char *fmt
, ...)
488 char *value
, *p
, *base64
;
489 DATA_BLOB base64_blob
;
490 bool do_base64
= false;
494 value
= talloc_vasprintf(NULL
, fmt
, ap
);
497 SMB_ASSERT(value
!= NULL
);
499 for (p
=value
; *p
; p
++) {
507 bool only_whitespace
= true;
508 for (p
=value
; *p
; p
++) {
510 * I know that this not multibyte safe, but we break
511 * on the first non-whitespace character anyway.
514 only_whitespace
= false;
518 if (only_whitespace
) {
524 res
= fprintf(add_fd
, "%s: %s\n", attr_name
, value
);
529 base64_blob
.data
= (unsigned char *)value
;
530 base64_blob
.length
= strlen(value
);
532 base64
= base64_encode_data_blob(value
, base64_blob
);
533 SMB_ASSERT(base64
!= NULL
);
535 res
= fprintf(add_fd
, "%s:: %s\n", attr_name
, base64
);
540 /****************************************************************
541 ****************************************************************/
543 static NTSTATUS
fetch_group_info_to_ldif(TALLOC_CTX
*mem_ctx
,
544 struct netr_DELTA_GROUP
*r
,
550 const char *groupname
= r
->group_name
.string
;
551 uint32 grouptype
= 0, g_rid
= 0;
552 char *group_attr
= sstring_sub(lp_ldap_group_suffix(), '=', ',');
554 /* Set up the group type (always 2 for group info) */
557 /* These groups are entered by populate_ldap_for_ldif */
558 if (strcmp(groupname
, "Domain Admins") == 0 ||
559 strcmp(groupname
, "Domain Users") == 0 ||
560 strcmp(groupname
, "Domain Guests") == 0 ||
561 strcmp(groupname
, "Domain Computers") == 0 ||
562 strcmp(groupname
, "Administrators") == 0 ||
563 strcmp(groupname
, "Print Operators") == 0 ||
564 strcmp(groupname
, "Backup Operators") == 0 ||
565 strcmp(groupname
, "Replicators") == 0) {
566 SAFE_FREE(group_attr
);
569 /* Increment the gid for the new group */
573 /* Map the group rid, gid, and dn */
575 groupmap
->rid
= g_rid
;
576 groupmap
->gidNumber
= ldif_gid
;
577 groupmap
->sambaSID
= talloc_asprintf(mem_ctx
, "%s-%d", sid
, g_rid
);
578 groupmap
->group_dn
= talloc_asprintf(mem_ctx
,
579 "cn=%s,ou=%s,%s", groupname
, group_attr
, suffix
);
580 if (groupmap
->sambaSID
== NULL
|| groupmap
->group_dn
== NULL
) {
581 SAFE_FREE(group_attr
);
582 return NT_STATUS_NO_MEMORY
;
585 /* Write the data to the temporary add ldif file */
586 fprintf(add_fd
, "# %s, %s, %s\n", groupname
, group_attr
,
588 fprintf_attr(add_fd
, "dn", "cn=%s,ou=%s,%s", groupname
, group_attr
,
590 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
591 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
592 fprintf_attr(add_fd
, "cn", "%s", groupname
);
593 fprintf(add_fd
, "gidNumber: %d\n", ldif_gid
);
594 fprintf(add_fd
, "sambaSID: %s\n", groupmap
->sambaSID
);
595 fprintf(add_fd
, "sambaGroupType: %d\n", grouptype
);
596 fprintf_attr(add_fd
, "displayName", "%s", groupname
);
597 fprintf(add_fd
, "\n");
600 SAFE_FREE(group_attr
);
605 /****************************************************************
606 ****************************************************************/
608 static NTSTATUS
fetch_account_info_to_ldif(TALLOC_CTX
*mem_ctx
,
609 struct netr_DELTA_USER
*r
,
611 ACCOUNTMAP
*accountmap
,
617 fstring username
, logonscript
, homedrive
, homepath
= "", homedir
= "";
618 fstring hex_nt_passwd
, hex_lm_passwd
;
619 fstring description
, profilepath
, fullname
, sambaSID
;
620 char *flags
, *user_rdn
;
622 const char* nopasswd
= "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
624 uint32 rid
= 0, group_rid
= 0, gidNumber
= 0;
628 memset(zero_buf
, '\0', sizeof(zero_buf
));
630 /* Get the username */
631 fstrcpy(username
, r
->account_name
.string
);
636 /* Map the rid and username for group member info later */
637 accountmap
->rid
= rid
;
638 accountmap
->cn
= talloc_strdup(mem_ctx
, username
);
639 NT_STATUS_HAVE_NO_MEMORY(accountmap
->cn
);
641 /* Get the home directory */
642 if (r
->acct_flags
& ACB_NORMAL
) {
643 fstrcpy(homedir
, r
->home_directory
.string
);
645 snprintf(homedir
, sizeof(homedir
), "/home/%s", username
);
647 snprintf(homedir
, sizeof(homedir
), "/nobodyshomedir");
649 ou
= lp_ldap_user_suffix();
651 ou
= lp_ldap_machine_suffix();
652 snprintf(homedir
, sizeof(homedir
), "/machinehomedir");
655 /* Get the logon script */
656 fstrcpy(logonscript
, r
->logon_script
.string
);
658 /* Get the home drive */
659 fstrcpy(homedrive
, r
->home_drive
.string
);
661 /* Get the home path */
662 fstrcpy(homepath
, r
->home_directory
.string
);
664 /* Get the description */
665 fstrcpy(description
, r
->description
.string
);
667 /* Get the display name */
668 fstrcpy(fullname
, r
->full_name
.string
);
670 /* Get the profile path */
671 fstrcpy(profilepath
, r
->profile_path
.string
);
673 /* Get lm and nt password data */
674 if (memcmp(r
->lmpassword
.hash
, zero_buf
, 16) != 0) {
675 pdb_sethexpwd(hex_lm_passwd
, r
->lmpassword
.hash
, r
->acct_flags
);
677 pdb_sethexpwd(hex_lm_passwd
, NULL
, 0);
679 if (memcmp(r
->ntpassword
.hash
, zero_buf
, 16) != 0) {
680 pdb_sethexpwd(hex_nt_passwd
, r
->ntpassword
.hash
, r
->acct_flags
);
682 pdb_sethexpwd(hex_nt_passwd
, NULL
, 0);
684 unix_time
= nt_time_to_unix(r
->last_password_change
);
686 /* Increment the uid for the new user */
689 /* Set up group id and sambaSID for the user */
690 group_rid
= r
->primary_gid
;
691 for (i
=0; i
<alloced
; i
++) {
692 if (groupmap
[i
].rid
== group_rid
) break;
695 DEBUG(1, ("Could not find rid %d in groupmap array\n",
697 return NT_STATUS_UNSUCCESSFUL
;
699 gidNumber
= groupmap
[i
].gidNumber
;
700 ret
= snprintf(sambaSID
, sizeof(sambaSID
), "%s", groupmap
[i
].sambaSID
);
701 if (ret
< 0 || ret
== sizeof(sambaSID
)) {
702 return NT_STATUS_UNSUCCESSFUL
;
705 /* Set up sambaAcctFlags */
706 flags
= pdb_encode_acct_ctrl(r
->acct_flags
,
707 NEW_PW_FORMAT_SPACE_PADDED_LEN
);
709 /* Add the user to the temporary add ldif file */
710 /* this isn't quite right...we can't assume there's just OU=. jmcd */
711 user_rdn
= sstring_sub(ou
, '=', ',');
712 fprintf(add_fd
, "# %s, %s, %s\n", username
, user_rdn
, suffix
);
713 fprintf_attr(add_fd
, "dn", "uid=%s,ou=%s,%s", username
, user_rdn
,
716 fprintf(add_fd
, "ObjectClass: top\n");
717 fprintf(add_fd
, "objectClass: inetOrgPerson\n");
718 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXACCOUNT
);
719 fprintf(add_fd
, "objectClass: shadowAccount\n");
720 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_SAMBASAMACCOUNT
);
721 fprintf_attr(add_fd
, "cn", "%s", username
);
722 fprintf_attr(add_fd
, "sn", "%s", username
);
723 fprintf_attr(add_fd
, "uid", "%s", username
);
724 fprintf(add_fd
, "uidNumber: %d\n", ldif_uid
);
725 fprintf(add_fd
, "gidNumber: %d\n", gidNumber
);
726 fprintf_attr(add_fd
, "homeDirectory", "%s", homedir
);
728 fprintf_attr(add_fd
, "sambaHomePath", "%s", homepath
);
730 fprintf_attr(add_fd
, "sambaHomeDrive", "%s", homedrive
);
732 fprintf_attr(add_fd
, "sambaLogonScript", "%s", logonscript
);
733 fprintf(add_fd
, "loginShell: %s\n",
734 ((r
->acct_flags
& ACB_NORMAL
) ?
735 "/bin/bash" : "/bin/false"));
736 fprintf(add_fd
, "gecos: System User\n");
738 fprintf_attr(add_fd
, "description", "%s", description
);
739 fprintf(add_fd
, "sambaSID: %s-%d\n", sid
, rid
);
740 fprintf(add_fd
, "sambaPrimaryGroupSID: %s\n", sambaSID
);
742 fprintf_attr(add_fd
, "displayName", "%s", fullname
);
744 fprintf_attr(add_fd
, "sambaProfilePath", "%s", profilepath
);
745 if (strcmp(nopasswd
, hex_lm_passwd
) != 0)
746 fprintf(add_fd
, "sambaLMPassword: %s\n", hex_lm_passwd
);
747 if (strcmp(nopasswd
, hex_nt_passwd
) != 0)
748 fprintf(add_fd
, "sambaNTPassword: %s\n", hex_nt_passwd
);
749 fprintf(add_fd
, "sambaPwdLastSet: %d\n", (int)unix_time
);
750 fprintf(add_fd
, "sambaAcctFlags: %s\n", flags
);
751 fprintf(add_fd
, "\n");
758 /****************************************************************
759 ****************************************************************/
761 static NTSTATUS
fetch_alias_info_to_ldif(TALLOC_CTX
*mem_ctx
,
762 struct netr_DELTA_ALIAS
*r
,
767 enum netr_SamDatabaseID database_id
)
769 fstring aliasname
, description
;
770 uint32 grouptype
= 0, g_rid
= 0;
771 char *group_attr
= sstring_sub(lp_ldap_group_suffix(), '=', ',');
773 /* Get the alias name */
774 fstrcpy(aliasname
, r
->alias_name
.string
);
776 /* Get the alias description */
777 fstrcpy(description
, r
->description
.string
);
779 /* Set up the group type */
780 switch (database_id
) {
781 case SAM_DATABASE_DOMAIN
:
784 case SAM_DATABASE_BUILTIN
:
793 These groups are entered by populate_ldap_for_ldif
794 Note that populate creates a group called Relicators,
795 but NT returns a group called Replicator
797 if (strcmp(aliasname
, "Domain Admins") == 0 ||
798 strcmp(aliasname
, "Domain Users") == 0 ||
799 strcmp(aliasname
, "Domain Guests") == 0 ||
800 strcmp(aliasname
, "Domain Computers") == 0 ||
801 strcmp(aliasname
, "Administrators") == 0 ||
802 strcmp(aliasname
, "Print Operators") == 0 ||
803 strcmp(aliasname
, "Backup Operators") == 0 ||
804 strcmp(aliasname
, "Replicator") == 0) {
805 SAFE_FREE(group_attr
);
808 /* Increment the gid for the new group */
812 /* Map the group rid and gid */
814 groupmap
->gidNumber
= ldif_gid
;
815 groupmap
->sambaSID
= talloc_asprintf(mem_ctx
, "%s-%d", sid
, g_rid
);
816 if (groupmap
->sambaSID
== NULL
) {
817 SAFE_FREE(group_attr
);
818 return NT_STATUS_NO_MEMORY
;
821 /* Write the data to the temporary add ldif file */
822 fprintf(add_fd
, "# %s, %s, %s\n", aliasname
, group_attr
,
824 fprintf_attr(add_fd
, "dn", "cn=%s,ou=%s,%s", aliasname
, group_attr
,
826 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_POSIXGROUP
);
827 fprintf(add_fd
, "objectClass: %s\n", LDAP_OBJ_GROUPMAP
);
828 fprintf(add_fd
, "cn: %s\n", aliasname
);
829 fprintf(add_fd
, "gidNumber: %d\n", ldif_gid
);
830 fprintf(add_fd
, "sambaSID: %s\n", groupmap
->sambaSID
);
831 fprintf(add_fd
, "sambaGroupType: %d\n", grouptype
);
832 fprintf_attr(add_fd
, "displayName", "%s", aliasname
);
834 fprintf_attr(add_fd
, "description", "%s", description
);
835 fprintf(add_fd
, "\n");
838 SAFE_FREE(group_attr
);
843 /****************************************************************
844 ****************************************************************/
846 static NTSTATUS
fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER
*r
,
849 ACCOUNTMAP
*accountmap
,
850 FILE *mod_fd
, int alloced
)
853 uint32 group_rid
= 0, rid
= 0;
856 /* Get the dn for the group */
857 if (r
->num_rids
> 0) {
859 for (j
=0; j
<alloced
; j
++) {
860 if (groupmap
[j
].rid
== group_rid
) break;
863 DEBUG(1, ("Could not find rid %d in groupmap array\n",
865 return NT_STATUS_UNSUCCESSFUL
;
867 snprintf(group_dn
, sizeof(group_dn
), "%s", groupmap
[j
].group_dn
);
868 fprintf(mod_fd
, "dn: %s\n", group_dn
);
870 /* Get the cn for each member */
871 for (i
=0; i
< r
->num_rids
; i
++) {
873 for (k
=0; k
<alloced
; k
++) {
874 if (accountmap
[k
].rid
== rid
) break;
877 DEBUG(1, ("Could not find rid %d in "
878 "accountmap array\n", rid
));
879 return NT_STATUS_UNSUCCESSFUL
;
881 fprintf(mod_fd
, "memberUid: %s\n", accountmap
[k
].cn
);
883 fprintf(mod_fd
, "\n");
891 /****************************************************************
892 ****************************************************************/
894 static NTSTATUS
ldif_init_context(TALLOC_CTX
*mem_ctx
,
895 enum netr_SamDatabaseID database_id
,
896 const char *ldif_filename
,
897 const char *domain_sid_str
,
898 struct samsync_ldif_context
**ctx
)
900 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
901 struct samsync_ldif_context
*r
;
902 const char *add_template
= "/tmp/add.ldif.XXXXXX";
903 const char *mod_template
= "/tmp/mod.ldif.XXXXXX";
904 const char *builtin_sid
= "S-1-5-32";
906 /* Get other smb.conf data */
907 if (!(lp_workgroup()) || !*(lp_workgroup())) {
908 DEBUG(0,("workgroup missing from smb.conf--exiting\n"));
912 /* Get the ldap suffix */
913 if (!(lp_ldap_suffix()) || !*(lp_ldap_suffix())) {
914 DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
918 if (*ctx
&& (*ctx
)->initialized
) {
922 r
= TALLOC_ZERO_P(mem_ctx
, struct samsync_ldif_context
);
923 NT_STATUS_HAVE_NO_MEMORY(r
);
925 /* Get the ldap suffix */
926 r
->suffix
= lp_ldap_suffix();
928 /* Ensure we have an output file */
930 r
->ldif_file
= fopen(ldif_filename
, "a");
932 r
->ldif_file
= stdout
;
936 fprintf(stderr
, "Could not open %s\n", ldif_filename
);
937 DEBUG(1, ("Could not open %s\n", ldif_filename
));
938 status
= NT_STATUS_UNSUCCESSFUL
;
942 r
->add_template
= talloc_strdup(mem_ctx
, add_template
);
943 r
->mod_template
= talloc_strdup(mem_ctx
, mod_template
);
944 if (!r
->add_template
|| !r
->mod_template
) {
945 status
= NT_STATUS_NO_MEMORY
;
949 r
->add_name
= talloc_strdup(mem_ctx
, add_template
);
950 r
->module_name
= talloc_strdup(mem_ctx
, mod_template
);
951 if (!r
->add_name
|| !r
->module_name
) {
952 status
= NT_STATUS_NO_MEMORY
;
956 /* Open the add and mod ldif files */
957 if (!(r
->add_file
= fdopen(mkstemp(r
->add_name
),"w"))) {
958 DEBUG(1, ("Could not open %s\n", r
->add_name
));
959 status
= NT_STATUS_UNSUCCESSFUL
;
962 if (!(r
->mod_file
= fdopen(mkstemp(r
->module_name
),"w"))) {
963 DEBUG(1, ("Could not open %s\n", r
->module_name
));
964 status
= NT_STATUS_UNSUCCESSFUL
;
968 /* Allocate initial memory for groupmap and accountmap arrays */
969 r
->groupmap
= TALLOC_ZERO_ARRAY(mem_ctx
, GROUPMAP
, 8);
970 r
->accountmap
= TALLOC_ZERO_ARRAY(mem_ctx
, ACCOUNTMAP
, 8);
971 if (r
->groupmap
== NULL
|| r
->accountmap
== NULL
) {
972 DEBUG(1,("GROUPMAP talloc failed\n"));
973 status
= NT_STATUS_NO_MEMORY
;
977 /* Remember how many we malloced */
980 /* Initial database population */
981 if (database_id
== SAM_DATABASE_DOMAIN
) {
983 status
= populate_ldap_for_ldif(domain_sid_str
,
987 if (!NT_STATUS_IS_OK(status
)) {
991 status
= map_populate_groups(mem_ctx
,
997 if (!NT_STATUS_IS_OK(status
)) {
1002 r
->initialized
= true;
1006 return NT_STATUS_OK
;
1012 /****************************************************************
1013 ****************************************************************/
1015 static void ldif_free_context(struct samsync_ldif_context
*r
)
1021 /* Close and delete the ldif files */
1023 fclose(r
->add_file
);
1026 if ((r
->add_name
!= NULL
) &&
1027 strcmp(r
->add_name
, r
->add_template
) && (unlink(r
->add_name
))) {
1028 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
1029 r
->add_name
, strerror(errno
)));
1033 fclose(r
->mod_file
);
1036 if ((r
->module_name
!= NULL
) &&
1037 strcmp(r
->module_name
, r
->mod_template
) && (unlink(r
->module_name
))) {
1038 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
1039 r
->module_name
, strerror(errno
)));
1042 if (r
->ldif_file
&& (r
->ldif_file
!= stdout
)) {
1043 fclose(r
->ldif_file
);
1049 /****************************************************************
1050 ****************************************************************/
1052 static void ldif_write_output(enum netr_SamDatabaseID database_id
,
1053 struct samsync_ldif_context
*l
)
1055 /* Write ldif data to the user's file */
1056 if (database_id
== SAM_DATABASE_DOMAIN
) {
1057 fprintf(l
->ldif_file
,
1058 "# SAM_DATABASE_DOMAIN: ADD ENTITIES\n");
1059 fprintf(l
->ldif_file
,
1060 "# =================================\n\n");
1061 fflush(l
->ldif_file
);
1062 } else if (database_id
== SAM_DATABASE_BUILTIN
) {
1063 fprintf(l
->ldif_file
,
1064 "# SAM_DATABASE_BUILTIN: ADD ENTITIES\n");
1065 fprintf(l
->ldif_file
,
1066 "# ==================================\n\n");
1067 fflush(l
->ldif_file
);
1069 fseek(l
->add_file
, 0, SEEK_SET
);
1070 transfer_file(fileno(l
->add_file
), fileno(l
->ldif_file
), (size_t) -1);
1072 if (database_id
== SAM_DATABASE_DOMAIN
) {
1073 fprintf(l
->ldif_file
,
1074 "# SAM_DATABASE_DOMAIN: MODIFY ENTITIES\n");
1075 fprintf(l
->ldif_file
,
1076 "# ====================================\n\n");
1077 fflush(l
->ldif_file
);
1078 } else if (database_id
== SAM_DATABASE_BUILTIN
) {
1079 fprintf(l
->ldif_file
,
1080 "# SAM_DATABASE_BUILTIN: MODIFY ENTITIES\n");
1081 fprintf(l
->ldif_file
,
1082 "# =====================================\n\n");
1083 fflush(l
->ldif_file
);
1085 fseek(l
->mod_file
, 0, SEEK_SET
);
1086 transfer_file(fileno(l
->mod_file
), fileno(l
->ldif_file
), (size_t) -1);
1089 /****************************************************************
1090 ****************************************************************/
1092 static NTSTATUS
fetch_sam_entry_ldif(TALLOC_CTX
*mem_ctx
,
1093 enum netr_SamDatabaseID database_id
,
1094 struct netr_DELTA_ENUM
*r
,
1095 struct samsync_context
*ctx
,
1096 uint32_t *a_index_p
,
1097 uint32_t *g_index_p
)
1099 union netr_DELTA_UNION u
= r
->delta_union
;
1100 union netr_DELTA_ID_UNION id
= r
->delta_id_union
;
1101 struct samsync_ldif_context
*l
=
1102 talloc_get_type_abort(ctx
->private_data
, struct samsync_ldif_context
);
1104 switch (r
->delta_type
) {
1105 case NETR_DELTA_DOMAIN
:
1108 case NETR_DELTA_GROUP
:
1109 fetch_group_info_to_ldif(mem_ctx
,
1111 &l
->groupmap
[*g_index_p
],
1113 ctx
->domain_sid_str
,
1118 case NETR_DELTA_USER
:
1119 fetch_account_info_to_ldif(mem_ctx
,
1122 &l
->accountmap
[*a_index_p
],
1124 ctx
->domain_sid_str
,
1130 case NETR_DELTA_ALIAS
:
1131 fetch_alias_info_to_ldif(mem_ctx
,
1133 &l
->groupmap
[*g_index_p
],
1135 ctx
->domain_sid_str
,
1141 case NETR_DELTA_GROUP_MEMBER
:
1142 fetch_groupmem_info_to_ldif(u
.group_member
,
1150 case NETR_DELTA_ALIAS_MEMBER
:
1151 case NETR_DELTA_POLICY
:
1152 case NETR_DELTA_ACCOUNT
:
1153 case NETR_DELTA_TRUSTED_DOMAIN
:
1154 case NETR_DELTA_SECRET
:
1155 case NETR_DELTA_RENAME_GROUP
:
1156 case NETR_DELTA_RENAME_USER
:
1157 case NETR_DELTA_RENAME_ALIAS
:
1158 case NETR_DELTA_DELETE_GROUP
:
1159 case NETR_DELTA_DELETE_USER
:
1160 case NETR_DELTA_MODIFY_COUNT
:
1163 } /* end of switch */
1165 return NT_STATUS_OK
;
1168 /****************************************************************
1169 ****************************************************************/
1171 static NTSTATUS
ldif_realloc_maps(TALLOC_CTX
*mem_ctx
,
1172 struct samsync_ldif_context
*l
,
1173 uint32_t num_entries
)
1175 /* Re-allocate memory for groupmap and accountmap arrays */
1176 l
->groupmap
= TALLOC_REALLOC_ARRAY(mem_ctx
,
1179 num_entries
+ l
->num_alloced
);
1181 l
->accountmap
= TALLOC_REALLOC_ARRAY(mem_ctx
,
1184 num_entries
+ l
->num_alloced
);
1186 if (l
->groupmap
== NULL
|| l
->accountmap
== NULL
) {
1187 DEBUG(1,("GROUPMAP talloc failed\n"));
1188 return NT_STATUS_NO_MEMORY
;
1191 /* Initialize the new records */
1192 memset(&(l
->groupmap
[l
->num_alloced
]), 0,
1193 sizeof(GROUPMAP
) * num_entries
);
1194 memset(&(l
->accountmap
[l
->num_alloced
]), 0,
1195 sizeof(ACCOUNTMAP
) * num_entries
);
1197 /* Remember how many we alloced this time */
1198 l
->num_alloced
+= num_entries
;
1200 return NT_STATUS_OK
;
1203 /****************************************************************
1204 ****************************************************************/
1206 static NTSTATUS
init_ldif(TALLOC_CTX
*mem_ctx
,
1207 struct samsync_context
*ctx
,
1208 enum netr_SamDatabaseID database_id
,
1209 uint64_t *sequence_num
)
1212 struct samsync_ldif_context
*ldif_ctx
=
1213 (struct samsync_ldif_context
*)ctx
->private_data
;
1215 status
= ldif_init_context(mem_ctx
,
1217 ctx
->output_filename
,
1218 ctx
->domain_sid_str
,
1220 if (!NT_STATUS_IS_OK(status
)) {
1224 ctx
->private_data
= ldif_ctx
;
1226 return NT_STATUS_OK
;
1229 /****************************************************************
1230 ****************************************************************/
1232 static NTSTATUS
fetch_sam_entries_ldif(TALLOC_CTX
*mem_ctx
,
1233 enum netr_SamDatabaseID database_id
,
1234 struct netr_DELTA_ENUM_ARRAY
*r
,
1235 uint64_t *sequence_num
,
1236 struct samsync_context
*ctx
)
1240 struct samsync_ldif_context
*ldif_ctx
=
1241 (struct samsync_ldif_context
*)ctx
->private_data
;
1243 status
= ldif_realloc_maps(mem_ctx
, ldif_ctx
, r
->num_deltas
);
1244 if (!NT_STATUS_IS_OK(status
)) {
1248 for (i
= 0; i
< r
->num_deltas
; i
++) {
1249 status
= fetch_sam_entry_ldif(mem_ctx
, database_id
,
1250 &r
->delta_enum
[i
], ctx
,
1251 &a_index
, &g_index
);
1252 if (!NT_STATUS_IS_OK(status
)) {
1257 return NT_STATUS_OK
;
1260 ldif_free_context(ldif_ctx
);
1261 ctx
->private_data
= NULL
;
1266 /****************************************************************
1267 ****************************************************************/
1269 static NTSTATUS
close_ldif(TALLOC_CTX
*mem_ctx
,
1270 struct samsync_context
*ctx
,
1271 enum netr_SamDatabaseID database_id
,
1272 uint64_t sequence_num
)
1274 struct samsync_ldif_context
*ldif_ctx
=
1275 (struct samsync_ldif_context
*)ctx
->private_data
;
1277 /* This was the last query */
1278 ldif_write_output(database_id
, ldif_ctx
);
1279 if (ldif_ctx
->ldif_file
!= stdout
) {
1280 ctx
->result_message
= talloc_asprintf(ctx
,
1281 "Vampired %d accounts and %d groups to %s",
1282 a_index
, g_index
, ctx
->output_filename
);
1285 ldif_free_context(ldif_ctx
);
1286 ctx
->private_data
= NULL
;
1288 return NT_STATUS_OK
;
1291 #else /* HAVE_LDAP */
1293 static NTSTATUS
init_ldif(TALLOC_CTX
*mem_ctx
,
1294 struct samsync_context
*ctx
,
1295 enum netr_SamDatabaseID database_id
,
1296 uint64_t *sequence_num
)
1298 return NT_STATUS_NOT_SUPPORTED
;
1301 static NTSTATUS
fetch_sam_entries_ldif(TALLOC_CTX
*mem_ctx
,
1302 enum netr_SamDatabaseID database_id
,
1303 struct netr_DELTA_ENUM_ARRAY
*r
,
1304 uint64_t *sequence_num
,
1305 struct samsync_context
*ctx
)
1307 return NT_STATUS_NOT_SUPPORTED
;
1310 static NTSTATUS
close_ldif(TALLOC_CTX
*mem_ctx
,
1311 struct samsync_context
*ctx
,
1312 enum netr_SamDatabaseID database_id
,
1313 uint64_t sequence_num
)
1315 return NT_STATUS_NOT_SUPPORTED
;
1320 const struct samsync_ops libnet_samsync_ldif_ops
= {
1321 .startup
= init_ldif
,
1322 .process_objects
= fetch_sam_entries_ldif
,
1323 .finish
= close_ldif
,