2 Unix SMB/CIFS implementation.
4 Extract the user/system database from a remote SamSync server
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
7 Copyright (C) Andrew Tridgell 2004
8 Copyright (C) Volker Lendecke 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include "libnet/libnet.h"
28 #include "librpc/gen_ndr/ndr_netlogon.h"
29 #include "librpc/gen_ndr/ndr_samr.h"
30 #include "dlinklist.h"
31 #include "lib/ldb/include/ldb.h"
33 struct samsync_ldb_secret
{
34 struct samsync_ldb_secret
*prev
, *next
;
40 struct samsync_ldb_trusted_domain
{
41 struct samsync_ldb_trusted_domain
*prev
, *next
;
46 struct samsync_ldb_state
{
47 struct dom_sid
*dom_sid
[3];
48 struct ldb_context
*sam_ldb
;
49 struct ldb_dn
*base_dn
[3];
50 struct samsync_ldb_secret
*secrets
;
51 struct samsync_ldb_trusted_domain
*trusted_domains
;
54 static NTSTATUS
samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX
*mem_ctx
,
55 struct samsync_ldb_state
*state
,
57 struct ldb_dn
**fsp_dn
)
59 const char *sidstr
= dom_sid_string(mem_ctx
, sid
);
60 /* We assume that ForeignSecurityPrincipals are under the BASEDN of the main domain */
61 struct ldb_dn
*basedn
= samdb_search_dn(state
->sam_ldb
, mem_ctx
,
62 state
->base_dn
[SAM_DATABASE_DOMAIN
],
63 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
64 struct ldb_message
*msg
;
68 return NT_STATUS_NO_MEMORY
;
72 DEBUG(0, ("Failed to find DN for "
73 "ForeignSecurityPrincipal container\n"));
74 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
77 msg
= ldb_msg_new(mem_ctx
);
79 return NT_STATUS_NO_MEMORY
;
82 /* add core elements to the ldb_message for the alias */
83 msg
->dn
= ldb_dn_build_child(mem_ctx
, "CN", sidstr
, basedn
);
85 return NT_STATUS_NO_MEMORY
;
87 samdb_msg_add_string(state
->sam_ldb
, mem_ctx
, msg
,
89 "foreignSecurityPrincipal");
93 /* create the alias */
94 ret
= samdb_add(state
->sam_ldb
, mem_ctx
, msg
);
96 DEBUG(0,("Failed to create foreignSecurityPrincipal "
98 ldb_dn_linearize(mem_ctx
, msg
->dn
),
99 ldb_errstring(state
->sam_ldb
)));
100 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
105 static NTSTATUS
samsync_ldb_handle_domain(TALLOC_CTX
*mem_ctx
,
106 struct samsync_ldb_state
*state
,
107 struct creds_CredentialState
*creds
,
108 enum netr_SamDatabaseID database
,
109 struct netr_DELTA_ENUM
*delta
)
111 struct netr_DELTA_DOMAIN
*domain
= delta
->delta_union
.domain
;
112 const char *domain_name
= domain
->domain_name
.string
;
113 struct ldb_message
*msg
;
116 if (database
== SAM_DATABASE_DOMAIN
) {
117 const char *domain_attrs
[] = {"nETBIOSName", "nCName", NULL
};
118 struct ldb_message
**msgs_domain
;
122 ret_domain
= gendb_search(state
->sam_ldb
, mem_ctx
, NULL
, &msgs_domain
, domain_attrs
,
123 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
125 if (ret_domain
== -1) {
126 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
129 if (ret_domain
!= 1) {
130 return NT_STATUS_NO_SUCH_DOMAIN
;
133 state
->base_dn
[database
] = samdb_result_dn(state
, msgs_domain
[0], "nCName", NULL
);
135 base_dn
= ldb_dn_linearize(mem_ctx
, state
->base_dn
[database
]);
137 state
->dom_sid
[database
] = samdb_search_dom_sid(state
->sam_ldb
, state
,
138 state
->base_dn
[database
],
139 "objectSid", "dn=%s", base_dn
);
140 } else if (database
== SAM_DATABASE_BUILTIN
) {
141 /* work out the builtin_dn - useful for so many calls its worth
143 const char *dnstring
= samdb_search_string(state
->sam_ldb
, mem_ctx
, NULL
,
144 "dn", "objectClass=builtinDomain");
145 state
->base_dn
[database
] = ldb_dn_explode(state
, dnstring
);
146 state
->dom_sid
[database
] = dom_sid_parse_talloc(state
, SID_BUILTIN
);
149 return NT_STATUS_INVALID_PARAMETER
;
152 msg
= ldb_msg_new(mem_ctx
);
154 return NT_STATUS_NO_MEMORY
;
157 msg
->dn
= talloc_reference(mem_ctx
, state
->base_dn
[database
]);
159 return NT_STATUS_NO_MEMORY
;
162 samdb_msg_add_string(state
->sam_ldb
, mem_ctx
,
163 msg
, "oEMInformation", domain
->comment
.string
);
165 samdb_msg_add_int64(state
->sam_ldb
, mem_ctx
,
166 msg
, "forceLogoff", domain
->force_logoff_time
);
168 samdb_msg_add_uint(state
->sam_ldb
, mem_ctx
,
169 msg
, "minPwdLen", domain
->min_password_length
);
171 samdb_msg_add_int64(state
->sam_ldb
, mem_ctx
,
172 msg
, "maxPwdAge", domain
->max_password_age
);
174 samdb_msg_add_int64(state
->sam_ldb
, mem_ctx
,
175 msg
, "minPwdAge", domain
->min_password_age
);
177 samdb_msg_add_uint(state
->sam_ldb
, mem_ctx
,
178 msg
, "pwdHistoryLength", domain
->password_history_length
);
180 samdb_msg_add_uint64(state
->sam_ldb
, mem_ctx
,
181 msg
, "modifiedCount",
182 domain
->sequence_num
);
184 samdb_msg_add_uint64(state
->sam_ldb
, mem_ctx
,
185 msg
, "creationTime", domain
->domain_create_time
);
187 /* TODO: Account lockout, password properties */
189 ret
= samdb_replace(state
->sam_ldb
, mem_ctx
, msg
);
192 return NT_STATUS_INTERNAL_ERROR
;
197 static NTSTATUS
samsync_ldb_handle_user(TALLOC_CTX
*mem_ctx
,
198 struct samsync_ldb_state
*state
,
199 struct creds_CredentialState
*creds
,
200 enum netr_SamDatabaseID database
,
201 struct netr_DELTA_ENUM
*delta
)
203 uint32_t rid
= delta
->delta_id_union
.rid
;
204 struct netr_DELTA_USER
*user
= delta
->delta_union
.user
;
205 const char *container
, *obj_class
;
209 struct ldb_message
*msg
;
210 struct ldb_message
**msgs
;
214 const char *attrs
[] = { NULL
};
216 msg
= ldb_msg_new(mem_ctx
);
218 return NT_STATUS_NO_MEMORY
;
221 /* search for the user, by rid */
222 ret
= gendb_search(state
->sam_ldb
, mem_ctx
, state
->base_dn
[database
],
223 &msgs
, attrs
, "(&(objectClass=user)(objectSid=%s))",
224 ldap_encode_ndr_dom_sid(mem_ctx
, dom_sid_add_rid(mem_ctx
, state
->dom_sid
[database
], rid
)));
227 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
228 } else if (ret
== 0) {
230 } else if (ret
> 1) {
231 DEBUG(0, ("More than one user with SID: %s\n",
232 dom_sid_string(mem_ctx
,
233 dom_sid_add_rid(mem_ctx
,
234 state
->dom_sid
[database
],
236 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
238 msg
->dn
= talloc_steal(msg
, msgs
[0]->dn
);
242 cn_name
= talloc_strdup(mem_ctx
, user
->account_name
.string
);
243 NT_STATUS_HAVE_NO_MEMORY(cn_name
);
244 cn_name_len
= strlen(cn_name
);
246 #define ADD_OR_DEL(type, attrib, field) do {\
248 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
249 attrib, user->field); \
251 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
256 ADD_OR_DEL(string
, "samAccountName", account_name
.string
);
257 ADD_OR_DEL(string
, "displayName", full_name
.string
);
259 if (samdb_msg_add_dom_sid(state
->sam_ldb
, mem_ctx
, msg
,
260 "objectSid", dom_sid_add_rid(mem_ctx
, state
->dom_sid
[database
], rid
))) {
261 return NT_STATUS_NO_MEMORY
;
264 ADD_OR_DEL(uint
, "primaryGroupID", primary_gid
);
265 ADD_OR_DEL(string
, "homeDirectory", home_directory
.string
);
266 ADD_OR_DEL(string
, "homeDrive", home_drive
.string
);
267 ADD_OR_DEL(string
, "scriptPath", logon_script
.string
);
268 ADD_OR_DEL(string
, "description", description
.string
);
269 ADD_OR_DEL(string
, "userWorkstations", workstations
.string
);
271 ADD_OR_DEL(uint64
, "lastLogon", last_logon
);
272 ADD_OR_DEL(uint64
, "lastLogoff", last_logoff
);
274 if (samdb_msg_add_logon_hours(state
->sam_ldb
, mem_ctx
, msg
, "logonHours", &user
->logon_hours
) != 0) {
275 return NT_STATUS_NO_MEMORY
;
278 ADD_OR_DEL(uint
, "badPwdCount", bad_password_count
);
279 ADD_OR_DEL(uint
, "logonCount", logon_count
);
281 ADD_OR_DEL(uint64
, "pwdLastSet", last_password_change
);
282 ADD_OR_DEL(uint64
, "accountExpires", acct_expiry
);
284 if (samdb_msg_add_acct_flags(state
->sam_ldb
, mem_ctx
, msg
,
285 "userAccountControl", user
->acct_flags
) != 0) {
286 return NT_STATUS_NO_MEMORY
;
290 samdb_msg_add_delete(state
->sam_ldb
, mem_ctx
, msg
,
292 if (user
->lm_password_present
) {
293 samdb_msg_add_hash(state
->sam_ldb
, mem_ctx
, msg
,
294 "lmPwdHash", &user
->lmpassword
);
296 samdb_msg_add_delete(state
->sam_ldb
, mem_ctx
, msg
,
299 if (user
->nt_password_present
) {
300 samdb_msg_add_hash(state
->sam_ldb
, mem_ctx
, msg
,
301 "ntPwdHash", &user
->ntpassword
);
303 samdb_msg_add_delete(state
->sam_ldb
, mem_ctx
, msg
,
307 ADD_OR_DEL(string
, "comment", comment
.string
);
308 ADD_OR_DEL(string
, "userParameters", parameters
.string
);
309 ADD_OR_DEL(uint
, "countryCode", country_code
);
310 ADD_OR_DEL(uint
, "codePage", code_page
);
312 ADD_OR_DEL(string
, "profilePath", profile_path
.string
);
316 acb
= user
->acct_flags
;
317 if (acb
& (ACB_WSTRUST
)) {
318 cn_name
[cn_name_len
- 1] = '\0';
319 container
= "Computers";
320 obj_class
= "computer";
322 } else if (acb
& ACB_SVRTRUST
) {
323 if (cn_name
[cn_name_len
- 1] != '$') {
324 return NT_STATUS_FOOBAR
;
326 cn_name
[cn_name_len
- 1] = '\0';
327 container
= "Domain Controllers";
328 obj_class
= "computer";
334 samdb_msg_add_string(state
->sam_ldb
, mem_ctx
, msg
,
335 "objectClass", obj_class
);
336 msg
->dn
= ldb_dn_string_compose(mem_ctx
, state
->base_dn
[database
],
337 "CN=%s, CN=%s", cn_name
, container
);
339 return NT_STATUS_NO_MEMORY
;
342 ret
= samdb_add(state
->sam_ldb
, mem_ctx
, msg
);
344 DEBUG(0,("Failed to create user record %s\n",
345 ldb_dn_linearize(mem_ctx
, msg
->dn
)));
346 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
349 ret
= samdb_replace(state
->sam_ldb
, mem_ctx
, msg
);
351 DEBUG(0,("Failed to modify user record %s\n",
352 ldb_dn_linearize(mem_ctx
, msg
->dn
)));
353 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
360 static NTSTATUS
samsync_ldb_delete_user(TALLOC_CTX
*mem_ctx
,
361 struct samsync_ldb_state
*state
,
362 struct creds_CredentialState
*creds
,
363 enum netr_SamDatabaseID database
,
364 struct netr_DELTA_ENUM
*delta
)
366 uint32_t rid
= delta
->delta_id_union
.rid
;
367 struct ldb_message
**msgs
;
369 const char *attrs
[] = { NULL
};
371 /* search for the user, by rid */
372 ret
= gendb_search(state
->sam_ldb
, mem_ctx
, state
->base_dn
[database
],
373 &msgs
, attrs
, "(&(objectClass=user)(objectSid=%s))",
374 ldap_encode_ndr_dom_sid(mem_ctx
, dom_sid_add_rid(mem_ctx
, state
->dom_sid
[database
], rid
)));
377 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state
->sam_ldb
)));
378 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
379 } else if (ret
== 0) {
380 return NT_STATUS_NO_SUCH_USER
;
381 } else if (ret
> 1) {
382 DEBUG(0, ("More than one user with SID: %s\n",
383 dom_sid_string(mem_ctx
,
384 dom_sid_add_rid(mem_ctx
,
385 state
->dom_sid
[database
],
387 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
390 ret
= samdb_delete(state
->sam_ldb
, mem_ctx
, msgs
[0]->dn
);
392 DEBUG(0,("Failed to delete user record %s: %s\n",
393 ldb_dn_linearize(mem_ctx
, msgs
[0]->dn
),
394 ldb_errstring(state
->sam_ldb
)));
395 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
401 static NTSTATUS
samsync_ldb_handle_group(TALLOC_CTX
*mem_ctx
,
402 struct samsync_ldb_state
*state
,
403 struct creds_CredentialState
*creds
,
404 enum netr_SamDatabaseID database
,
405 struct netr_DELTA_ENUM
*delta
)
407 uint32_t rid
= delta
->delta_id_union
.rid
;
408 struct netr_DELTA_GROUP
*group
= delta
->delta_union
.group
;
409 const char *container
, *obj_class
;
412 struct ldb_message
*msg
;
413 struct ldb_message
**msgs
;
416 const char *attrs
[] = { NULL
};
418 msg
= ldb_msg_new(mem_ctx
);
420 return NT_STATUS_NO_MEMORY
;
423 /* search for the group, by rid */
424 ret
= gendb_search(state
->sam_ldb
, mem_ctx
, state
->base_dn
[database
], &msgs
, attrs
,
425 "(&(objectClass=group)(objectSid=%s))",
426 ldap_encode_ndr_dom_sid(mem_ctx
, dom_sid_add_rid(mem_ctx
, state
->dom_sid
[database
], rid
)));
429 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state
->sam_ldb
)));
430 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
431 } else if (ret
== 0) {
433 } else if (ret
> 1) {
434 DEBUG(0, ("More than one group/alias with SID: %s\n",
435 dom_sid_string(mem_ctx
,
436 dom_sid_add_rid(mem_ctx
,
437 state
->dom_sid
[database
],
439 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
441 msg
->dn
= talloc_steal(msg
, msgs
[0]->dn
);
444 cn_name
= group
->group_name
.string
;
446 #define ADD_OR_DEL(type, attrib, field) do {\
447 if (group->field) { \
448 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
449 attrib, group->field); \
451 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
456 ADD_OR_DEL(string
, "samAccountName", group_name
.string
);
458 if (samdb_msg_add_dom_sid(state
->sam_ldb
, mem_ctx
, msg
,
459 "objectSid", dom_sid_add_rid(mem_ctx
, state
->dom_sid
[database
], rid
))) {
460 return NT_STATUS_NO_MEMORY
;
463 ADD_OR_DEL(string
, "description", description
.string
);
471 samdb_msg_add_string(state
->sam_ldb
, mem_ctx
, msg
,
472 "objectClass", obj_class
);
473 msg
->dn
= ldb_dn_string_compose(mem_ctx
, state
->base_dn
[database
],
474 "CN=%s, CN=%s", cn_name
, container
);
476 return NT_STATUS_NO_MEMORY
;
479 ret
= samdb_add(state
->sam_ldb
, mem_ctx
, msg
);
481 DEBUG(0,("Failed to create group record %s: %s\n",
482 ldb_dn_linearize(mem_ctx
, msg
->dn
),
483 ldb_errstring(state
->sam_ldb
)));
484 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
487 ret
= samdb_replace(state
->sam_ldb
, mem_ctx
, msg
);
489 DEBUG(0,("Failed to modify group record %s: %s\n",
490 ldb_dn_linearize(mem_ctx
, msg
->dn
),
491 ldb_errstring(state
->sam_ldb
)));
492 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
499 static NTSTATUS
samsync_ldb_delete_group(TALLOC_CTX
*mem_ctx
,
500 struct samsync_ldb_state
*state
,
501 struct creds_CredentialState
*creds
,
502 enum netr_SamDatabaseID database
,
503 struct netr_DELTA_ENUM
*delta
)
505 uint32_t rid
= delta
->delta_id_union
.rid
;
506 struct ldb_message
**msgs
;
508 const char *attrs
[] = { NULL
};
510 /* search for the group, by rid */
511 ret
= gendb_search(state
->sam_ldb
, mem_ctx
, state
->base_dn
[database
], &msgs
, attrs
,
512 "(&(objectClass=group)(objectSid=%s))",
513 ldap_encode_ndr_dom_sid(mem_ctx
, dom_sid_add_rid(mem_ctx
, state
->dom_sid
[database
], rid
)));
516 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state
->sam_ldb
)));
517 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
518 } else if (ret
== 0) {
519 return NT_STATUS_NO_SUCH_GROUP
;
520 } else if (ret
> 1) {
521 DEBUG(0, ("More than one group/alias with SID: %s\n",
522 dom_sid_string(mem_ctx
,
523 dom_sid_add_rid(mem_ctx
,
524 state
->dom_sid
[database
],
526 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
529 ret
= samdb_delete(state
->sam_ldb
, mem_ctx
, msgs
[0]->dn
);
531 DEBUG(0,("Failed to delete group record %s: %s\n",
532 ldb_dn_linearize(mem_ctx
, msgs
[0]->dn
),
533 ldb_errstring(state
->sam_ldb
)));
534 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
540 static NTSTATUS
samsync_ldb_handle_group_member(TALLOC_CTX
*mem_ctx
,
541 struct samsync_ldb_state
*state
,
542 struct creds_CredentialState
*creds
,
543 enum netr_SamDatabaseID database
,
544 struct netr_DELTA_ENUM
*delta
)
546 uint32_t rid
= delta
->delta_id_union
.rid
;
547 struct netr_DELTA_GROUP_MEMBER
*group_member
= delta
->delta_union
.group_member
;
548 struct ldb_message
*msg
;
549 struct ldb_message
**msgs
;
551 const char *attrs
[] = { NULL
};
554 msg
= ldb_msg_new(mem_ctx
);
556 return NT_STATUS_NO_MEMORY
;
559 /* search for the group, by rid */
560 ret
= gendb_search(state
->sam_ldb
, mem_ctx
, state
->base_dn
[database
], &msgs
, attrs
,
561 "(&(objectClass=group)(objectSid=%s))",
562 ldap_encode_ndr_dom_sid(mem_ctx
, dom_sid_add_rid(mem_ctx
, state
->dom_sid
[database
], rid
)));
565 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state
->sam_ldb
)));
566 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
567 } else if (ret
== 0) {
568 return NT_STATUS_NO_SUCH_GROUP
;
569 } else if (ret
> 1) {
570 DEBUG(0, ("More than one group/alias with SID: %s\n",
571 dom_sid_string(mem_ctx
,
572 dom_sid_add_rid(mem_ctx
,
573 state
->dom_sid
[database
],
575 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
577 msg
->dn
= talloc_steal(msg
, msgs
[0]->dn
);
582 for (i
=0; i
<group_member
->num_rids
; i
++) {
583 /* search for the group, by rid */
584 ret
= gendb_search(state
->sam_ldb
, mem_ctx
, state
->base_dn
[database
], &msgs
, attrs
,
585 "(&(objectClass=user)(objectSid=%s))",
586 ldap_encode_ndr_dom_sid(mem_ctx
, dom_sid_add_rid(mem_ctx
, state
->dom_sid
[database
], group_member
->rids
[i
])));
589 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state
->sam_ldb
)));
590 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
591 } else if (ret
== 0) {
592 return NT_STATUS_NO_SUCH_USER
;
593 } else if (ret
> 1) {
594 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
596 samdb_msg_add_string(state
->sam_ldb
, mem_ctx
, msg
, "member", ldb_dn_linearize(mem_ctx
, msgs
[0]->dn
));
602 ret
= samdb_replace(state
->sam_ldb
, mem_ctx
, msg
);
604 DEBUG(0,("Failed to modify group record %s: %s\n",
605 ldb_dn_linearize(mem_ctx
, msg
->dn
),
606 ldb_errstring(state
->sam_ldb
)));
607 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
613 static NTSTATUS
samsync_ldb_handle_alias(TALLOC_CTX
*mem_ctx
,
614 struct samsync_ldb_state
*state
,
615 struct creds_CredentialState
*creds
,
616 enum netr_SamDatabaseID database
,
617 struct netr_DELTA_ENUM
*delta
)
619 uint32_t rid
= delta
->delta_id_union
.rid
;
620 struct netr_DELTA_ALIAS
*alias
= delta
->delta_union
.alias
;
621 const char *container
, *obj_class
;
624 struct ldb_message
*msg
;
625 struct ldb_message
**msgs
;
628 const char *attrs
[] = { NULL
};
630 msg
= ldb_msg_new(mem_ctx
);
632 return NT_STATUS_NO_MEMORY
;
635 /* search for the alias, by rid */
636 ret
= gendb_search(state
->sam_ldb
, mem_ctx
, state
->base_dn
[database
], &msgs
, attrs
,
637 "(&(objectClass=group)(objectSid=%s))",
638 ldap_encode_ndr_dom_sid(mem_ctx
, dom_sid_add_rid(mem_ctx
, state
->dom_sid
[database
], rid
)));
641 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state
->sam_ldb
)));
642 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
643 } else if (ret
== 0) {
645 } else if (ret
> 1) {
646 DEBUG(0, ("More than one group/alias with SID: %s\n",
647 dom_sid_string(mem_ctx
,
648 dom_sid_add_rid(mem_ctx
,
649 state
->dom_sid
[database
],
651 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
653 msg
->dn
= talloc_steal(mem_ctx
, msgs
[0]->dn
);
656 cn_name
= alias
->alias_name
.string
;
658 #define ADD_OR_DEL(type, attrib, field) do {\
659 if (alias->field) { \
660 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
661 attrib, alias->field); \
663 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
668 ADD_OR_DEL(string
, "samAccountName", alias_name
.string
);
670 if (samdb_msg_add_dom_sid(state
->sam_ldb
, mem_ctx
, msg
,
671 "objectSid", dom_sid_add_rid(mem_ctx
, state
->dom_sid
[database
], rid
))) {
672 return NT_STATUS_NO_MEMORY
;
675 ADD_OR_DEL(string
, "description", description
.string
);
679 samdb_msg_add_uint(state
->sam_ldb
, mem_ctx
, msg
, "groupType", 0x80000004);
685 samdb_msg_add_string(state
->sam_ldb
, mem_ctx
, msg
,
686 "objectClass", obj_class
);
687 msg
->dn
= ldb_dn_string_compose(mem_ctx
, state
->base_dn
[database
],
688 "CN=%s, CN=%s", cn_name
, container
);
690 return NT_STATUS_NO_MEMORY
;
693 ret
= samdb_add(state
->sam_ldb
, mem_ctx
, msg
);
695 DEBUG(0,("Failed to create alias record %s: %s\n",
696 ldb_dn_linearize(mem_ctx
, msg
->dn
),
697 ldb_errstring(state
->sam_ldb
)));
698 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
701 ret
= samdb_replace(state
->sam_ldb
, mem_ctx
, msg
);
703 DEBUG(0,("Failed to modify alias record %s: %s\n",
704 ldb_dn_linearize(mem_ctx
, msg
->dn
),
705 ldb_errstring(state
->sam_ldb
)));
706 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
713 static NTSTATUS
samsync_ldb_delete_alias(TALLOC_CTX
*mem_ctx
,
714 struct samsync_ldb_state
*state
,
715 struct creds_CredentialState
*creds
,
716 enum netr_SamDatabaseID database
,
717 struct netr_DELTA_ENUM
*delta
)
719 uint32_t rid
= delta
->delta_id_union
.rid
;
720 struct ldb_message
**msgs
;
722 const char *attrs
[] = { NULL
};
724 /* search for the alias, by rid */
725 ret
= gendb_search(state
->sam_ldb
, mem_ctx
, state
->base_dn
[database
], &msgs
, attrs
,
726 "(&(objectClass=group)(objectSid=%s))",
727 ldap_encode_ndr_dom_sid(mem_ctx
, dom_sid_add_rid(mem_ctx
, state
->dom_sid
[database
], rid
)));
730 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state
->sam_ldb
)));
731 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
732 } else if (ret
== 0) {
733 return NT_STATUS_NO_SUCH_ALIAS
;
734 } else if (ret
> 1) {
735 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
738 ret
= samdb_delete(state
->sam_ldb
, mem_ctx
, msgs
[0]->dn
);
740 DEBUG(0,("Failed to delete alias record %s: %s\n",
741 ldb_dn_linearize(mem_ctx
, msgs
[0]->dn
),
742 ldb_errstring(state
->sam_ldb
)));
743 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
749 static NTSTATUS
samsync_ldb_handle_alias_member(TALLOC_CTX
*mem_ctx
,
750 struct samsync_ldb_state
*state
,
751 struct creds_CredentialState
*creds
,
752 enum netr_SamDatabaseID database
,
753 struct netr_DELTA_ENUM
*delta
)
755 uint32_t rid
= delta
->delta_id_union
.rid
;
756 struct netr_DELTA_ALIAS_MEMBER
*alias_member
= delta
->delta_union
.alias_member
;
757 struct ldb_message
*msg
;
758 struct ldb_message
**msgs
;
760 const char *attrs
[] = { NULL
};
763 msg
= ldb_msg_new(mem_ctx
);
765 return NT_STATUS_NO_MEMORY
;
768 /* search for the alias, by rid */
769 ret
= gendb_search(state
->sam_ldb
, mem_ctx
, state
->base_dn
[database
], &msgs
, attrs
,
770 "(&(objectClass=group)(objectSid=%s))",
771 ldap_encode_ndr_dom_sid(mem_ctx
, dom_sid_add_rid(mem_ctx
, state
->dom_sid
[database
], rid
)));
774 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state
->sam_ldb
)));
775 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
776 } else if (ret
== 0) {
777 return NT_STATUS_NO_SUCH_GROUP
;
778 } else if (ret
> 1) {
779 DEBUG(0, ("More than one group/alias with SID: %s\n",
780 dom_sid_string(mem_ctx
,
781 dom_sid_add_rid(mem_ctx
,
782 state
->dom_sid
[database
],
784 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
786 msg
->dn
= talloc_steal(msg
, msgs
[0]->dn
);
791 for (i
=0; i
<alias_member
->sids
.num_sids
; i
++) {
792 struct ldb_dn
*alias_member_dn
;
793 /* search for members, in the top basedn (normal users are builtin aliases) */
794 ret
= gendb_search(state
->sam_ldb
, mem_ctx
, state
->base_dn
[SAM_DATABASE_DOMAIN
], &msgs
, attrs
,
796 ldap_encode_ndr_dom_sid(mem_ctx
, alias_member
->sids
.sids
[i
].sid
));
799 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state
->sam_ldb
)));
800 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
801 } else if (ret
== 0) {
803 nt_status
= samsync_ldb_add_foreignSecurityPrincipal(mem_ctx
, state
,
804 alias_member
->sids
.sids
[i
].sid
,
806 if (!NT_STATUS_IS_OK(nt_status
)) {
809 } else if (ret
> 1) {
810 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
812 alias_member_dn
= msgs
[0]->dn
;
814 samdb_msg_add_string(state
->sam_ldb
, mem_ctx
, msg
, "member", ldb_dn_linearize(mem_ctx
, alias_member_dn
));
819 ret
= samdb_replace(state
->sam_ldb
, mem_ctx
, msg
);
821 DEBUG(0,("Failed to modify group record %s: %s\n",
822 ldb_dn_linearize(mem_ctx
, msg
->dn
),
823 ldb_errstring(state
->sam_ldb
)));
824 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
830 static NTSTATUS
samsync_ldb_handle_account(TALLOC_CTX
*mem_ctx
,
831 struct samsync_ldb_state
*state
,
832 struct creds_CredentialState
*creds
,
833 enum netr_SamDatabaseID database
,
834 struct netr_DELTA_ENUM
*delta
)
836 struct dom_sid
*sid
= delta
->delta_id_union
.sid
;
837 struct netr_DELTA_ACCOUNT
*account
= delta
->delta_union
.account
;
839 struct ldb_message
*msg
;
840 struct ldb_message
**msgs
;
841 struct ldb_dn
*privilege_dn
;
843 const char *attrs
[] = { NULL
};
846 msg
= ldb_msg_new(mem_ctx
);
848 return NT_STATUS_NO_MEMORY
;
851 /* search for the account, by sid, in the top basedn */
852 ret
= gendb_search(state
->sam_ldb
, mem_ctx
, state
->base_dn
[SAM_DATABASE_DOMAIN
], &msgs
, attrs
,
853 "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx
, sid
));
856 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state
->sam_ldb
)));
857 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
858 } else if (ret
== 0) {
860 nt_status
= samsync_ldb_add_foreignSecurityPrincipal(mem_ctx
, state
,
863 privilege_dn
= talloc_steal(msg
, privilege_dn
);
864 if (!NT_STATUS_IS_OK(nt_status
)) {
867 } else if (ret
> 1) {
868 DEBUG(0, ("More than one account with SID: %s\n",
869 dom_sid_string(mem_ctx
, sid
)));
870 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
872 privilege_dn
= talloc_steal(msg
, msgs
[0]->dn
);
875 msg
->dn
= privilege_dn
;
877 for (i
=0; i
< account
->privilege_entries
; i
++) {
878 samdb_msg_add_string(state
->sam_ldb
, mem_ctx
, msg
, "privilege",
879 account
->privilege_name
[i
].string
);
882 ret
= samdb_replace(state
->sam_ldb
, mem_ctx
, msg
);
884 DEBUG(0,("Failed to modify privilege record %s\n",
885 ldb_dn_linearize(mem_ctx
, msg
->dn
)));
886 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
892 static NTSTATUS
samsync_ldb_delete_account(TALLOC_CTX
*mem_ctx
,
893 struct samsync_ldb_state
*state
,
894 struct creds_CredentialState
*creds
,
895 enum netr_SamDatabaseID database
,
896 struct netr_DELTA_ENUM
*delta
)
898 struct dom_sid
*sid
= delta
->delta_id_union
.sid
;
900 struct ldb_message
*msg
;
901 struct ldb_message
**msgs
;
903 const char *attrs
[] = { NULL
};
905 msg
= ldb_msg_new(mem_ctx
);
907 return NT_STATUS_NO_MEMORY
;
910 /* search for the account, by sid, in the top basedn */
911 ret
= gendb_search(state
->sam_ldb
, mem_ctx
, state
->base_dn
[SAM_DATABASE_DOMAIN
], &msgs
, attrs
,
913 ldap_encode_ndr_dom_sid(mem_ctx
, sid
));
916 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state
->sam_ldb
)));
917 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
918 } else if (ret
== 0) {
919 return NT_STATUS_NO_SUCH_USER
;
920 } else if (ret
> 1) {
921 DEBUG(0, ("More than one account with SID: %s\n",
922 dom_sid_string(mem_ctx
, sid
)));
923 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
925 msg
->dn
= talloc_steal(msg
, msgs
[0]->dn
);
928 samdb_msg_add_delete(state
->sam_ldb
, mem_ctx
, msg
,
931 ret
= samdb_replace(state
->sam_ldb
, mem_ctx
, msg
);
933 DEBUG(0,("Failed to modify privilege record %s\n",
934 ldb_dn_linearize(mem_ctx
, msg
->dn
)));
935 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
941 static NTSTATUS
libnet_samsync_ldb_fn(TALLOC_CTX
*mem_ctx
,
943 struct creds_CredentialState
*creds
,
944 enum netr_SamDatabaseID database
,
945 struct netr_DELTA_ENUM
*delta
,
948 NTSTATUS nt_status
= NT_STATUS_OK
;
949 struct samsync_ldb_state
*state
= private;
951 *error_string
= NULL
;
952 switch (delta
->delta_type
) {
953 case NETR_DELTA_DOMAIN
:
955 nt_status
= samsync_ldb_handle_domain(mem_ctx
,
962 case NETR_DELTA_USER
:
964 nt_status
= samsync_ldb_handle_user(mem_ctx
,
971 case NETR_DELTA_DELETE_USER
:
973 nt_status
= samsync_ldb_delete_user(mem_ctx
,
980 case NETR_DELTA_GROUP
:
982 nt_status
= samsync_ldb_handle_group(mem_ctx
,
989 case NETR_DELTA_DELETE_GROUP
:
991 nt_status
= samsync_ldb_delete_group(mem_ctx
,
998 case NETR_DELTA_GROUP_MEMBER
:
1000 nt_status
= samsync_ldb_handle_group_member(mem_ctx
,
1007 case NETR_DELTA_ALIAS
:
1009 nt_status
= samsync_ldb_handle_alias(mem_ctx
,
1016 case NETR_DELTA_DELETE_ALIAS
:
1018 nt_status
= samsync_ldb_delete_alias(mem_ctx
,
1025 case NETR_DELTA_ALIAS_MEMBER
:
1027 nt_status
= samsync_ldb_handle_alias_member(mem_ctx
,
1034 case NETR_DELTA_ACCOUNT
:
1036 nt_status
= samsync_ldb_handle_account(mem_ctx
,
1043 case NETR_DELTA_DELETE_ACCOUNT
:
1045 nt_status
= samsync_ldb_delete_account(mem_ctx
,
1053 /* Can't dump them all right now */
1059 static NTSTATUS
libnet_samsync_ldb_netlogon(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, struct libnet_samsync_ldb
*r
)
1062 struct libnet_SamSync r2
;
1063 struct samsync_ldb_state
*state
= talloc(mem_ctx
, struct samsync_ldb_state
);
1066 return NT_STATUS_NO_MEMORY
;
1069 state
->secrets
= NULL
;
1070 state
->trusted_domains
= NULL
;
1072 state
->sam_ldb
= samdb_connect(state
);
1076 r2
.error_string
= NULL
;
1077 r2
.delta_fn
= libnet_samsync_ldb_fn
;
1079 r2
.machine_account
= NULL
; /* TODO: Create a machine account, fill this in, and the delete it */
1080 nt_status
= libnet_SamSync_netlogon(ctx
, state
, &r2
);
1081 r
->error_string
= r2
.error_string
;
1083 if (!NT_STATUS_IS_OK(nt_status
)) {
1093 static NTSTATUS
libnet_samsync_ldb_generic(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, struct libnet_samsync_ldb
*r
)
1096 struct libnet_samsync_ldb r2
;
1097 r2
.level
= LIBNET_SAMSYNC_LDB_NETLOGON
;
1098 r2
.error_string
= NULL
;
1099 nt_status
= libnet_samsync_ldb(ctx
, mem_ctx
, &r2
);
1100 r
->error_string
= r2
.error_string
;
1105 NTSTATUS
libnet_samsync_ldb(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
, struct libnet_samsync_ldb
*r
)
1108 case LIBNET_SAMSYNC_LDB_GENERIC
:
1109 return libnet_samsync_ldb_generic(ctx
, mem_ctx
, r
);
1110 case LIBNET_SAMSYNC_LDB_NETLOGON
:
1111 return libnet_samsync_ldb_netlogon(ctx
, mem_ctx
, r
);
1114 return NT_STATUS_INVALID_LEVEL
;