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;
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,
59 const char *sidstr = dom_sid_string(mem_ctx, sid);
60 /* We assume that ForeignSecurityPrincipals are under the BASEDN of the main domain */
61 const char *basedn = samdb_search_string(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN],
63 "(&(objectClass=container)"
64 "(cn=ForeignSecurityPrincipals))");
65 struct ldb_message *msg;
69 return NT_STATUS_NO_MEMORY;
73 DEBUG(0, ("Failed to find DN for "
74 "ForeignSecurityPrincipal container\n"));
75 return NT_STATUS_INTERNAL_DB_CORRUPTION;
78 msg = ldb_msg_new(mem_ctx);
80 return NT_STATUS_NO_MEMORY;
83 /* add core elements to the ldb_message for the alias */
84 msg->dn = talloc_asprintf(mem_ctx, "CN=%s,%s", sidstr, basedn);
86 return NT_STATUS_NO_MEMORY;
88 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
90 "foreignSecurityPrincipal");
94 /* create the alias */
95 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
97 DEBUG(0,("Failed to create foreignSecurityPrincipal "
98 "record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
99 return NT_STATUS_INTERNAL_DB_CORRUPTION;
104 static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
105 struct samsync_ldb_state *state,
106 struct creds_CredentialState *creds,
107 enum netr_SamDatabaseID database,
108 struct netr_DELTA_ENUM *delta)
110 struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;
111 const char *domain_name = domain->domain_name.string;
112 struct ldb_message *msg;
115 if (database == SAM_DATABASE_DOMAIN) {
116 const char *domain_attrs[] = {"nETBIOSName", "nCName", NULL};
117 struct ldb_message **msgs_domain;
119 ret_domain = gendb_search(state->sam_ldb, mem_ctx, NULL, &msgs_domain, domain_attrs,
120 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
122 if (ret_domain == -1) {
123 return NT_STATUS_INTERNAL_DB_CORRUPTION;
126 if (ret_domain != 1) {
127 return NT_STATUS_NO_SUCH_DOMAIN;
130 state->base_dn[database]
131 = talloc_steal(state, samdb_result_string(msgs_domain[0],
134 state->dom_sid[database]
135 = talloc_steal(state,
136 samdb_search_dom_sid(state->sam_ldb, state,
137 state->base_dn[database], "objectSid",
138 "dn=%s", state->base_dn[database]));
139 } else if (database == SAM_DATABASE_BUILTIN) {
140 /* work out the builtin_dn - useful for so many calls its worth
142 state->base_dn[database]
143 = talloc_steal(state,
144 samdb_search_string(state->sam_ldb, mem_ctx, NULL,
145 "dn", "objectClass=builtinDomain"));
146 state->dom_sid[database]
147 = dom_sid_parse_talloc(state, SID_BUILTIN);
150 return NT_STATUS_INVALID_PARAMETER;
153 msg = ldb_msg_new(mem_ctx);
155 return NT_STATUS_NO_MEMORY;
158 msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
160 return NT_STATUS_NO_MEMORY;
163 samdb_msg_add_string(state->sam_ldb, mem_ctx,
164 msg, "oEMInformation", domain->comment.string);
166 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
167 msg, "forceLogoff", domain->force_logoff_time);
169 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
170 msg, "minPwdLen", domain->min_password_length);
172 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
173 msg, "maxPwdAge", domain->max_password_age);
175 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
176 msg, "minPwdAge", domain->min_password_age);
178 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
179 msg, "pwdHistoryLength", domain->password_history_length);
181 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
182 msg, "modifiedCount",
183 domain->sequence_num);
185 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
186 msg, "creationTime", domain->domain_create_time);
188 /* TODO: Account lockout, password properties */
190 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
193 return NT_STATUS_INTERNAL_ERROR;
198 static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
199 struct samsync_ldb_state *state,
200 struct creds_CredentialState *creds,
201 enum netr_SamDatabaseID database,
202 struct netr_DELTA_ENUM *delta)
204 uint32_t rid = delta->delta_id_union.rid;
205 struct netr_DELTA_USER *user = delta->delta_union.user;
206 const char *container, *obj_class;
210 struct ldb_message *msg;
211 struct ldb_message **msgs;
215 const char *attrs[] = { NULL };
217 msg = ldb_msg_new(mem_ctx);
219 return NT_STATUS_NO_MEMORY;
222 /* search for the user, by rid */
223 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
224 "(&(objectClass=user)(objectSid=%s))",
225 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
228 return NT_STATUS_INTERNAL_DB_CORRUPTION;
229 } else if (ret == 0) {
231 } else if (ret > 1) {
232 DEBUG(0, ("More than one user with SID: %s\n",
233 dom_sid_string(mem_ctx,
234 dom_sid_add_rid(mem_ctx,
235 state->dom_sid[database],
237 return NT_STATUS_INTERNAL_DB_CORRUPTION;
239 msg->dn = talloc_steal(msg, msgs[0]->dn);
243 cn_name = talloc_strdup(mem_ctx, user->account_name.string);
244 NT_STATUS_HAVE_NO_MEMORY(cn_name);
245 cn_name_len = strlen(cn_name);
247 #define ADD_OR_DEL(type, attrib, field) do {\
249 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
250 attrib, user->field); \
252 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
257 ADD_OR_DEL(string, "samAccountName", account_name.string);
258 ADD_OR_DEL(string, "displayName", full_name.string);
260 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
261 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
262 return NT_STATUS_NO_MEMORY;
265 ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
266 ADD_OR_DEL(string, "homeDirectory", home_directory.string);
267 ADD_OR_DEL(string, "homeDrive", home_drive.string);
268 ADD_OR_DEL(string, "scriptPath", logon_script.string);
269 ADD_OR_DEL(string, "description", description.string);
270 ADD_OR_DEL(string, "userWorkstations", workstations.string);
272 ADD_OR_DEL(uint64, "lastLogon", last_logon);
273 ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
275 if (samdb_msg_add_logon_hours(state->sam_ldb, mem_ctx, msg, "logonHours", &user->logon_hours) != 0) {
276 return NT_STATUS_NO_MEMORY;
279 ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
280 ADD_OR_DEL(uint, "logonCount", logon_count);
282 ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
283 ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
285 if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg,
286 "userAccountControl", user->acct_flags) != 0) {
287 return NT_STATUS_NO_MEMORY;
291 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
293 if (user->lm_password_present) {
294 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
295 "lmPwdHash", &user->lmpassword);
297 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
300 if (user->nt_password_present) {
301 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
302 "ntPwdHash", &user->ntpassword);
304 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
308 ADD_OR_DEL(string, "comment", comment.string);
309 ADD_OR_DEL(string, "userParameters", parameters.string);
310 ADD_OR_DEL(uint, "countryCode", country_code);
311 ADD_OR_DEL(uint, "codePage", code_page);
313 ADD_OR_DEL(string, "profilePath", profile_path.string);
317 acb = user->acct_flags;
318 if (acb & (ACB_WSTRUST)) {
319 cn_name[cn_name_len - 1] = '\0';
320 container = "Computers";
321 obj_class = "computer";
323 } else if (acb & ACB_SVRTRUST) {
324 if (cn_name[cn_name_len - 1] != '$') {
325 return NT_STATUS_FOOBAR;
327 cn_name[cn_name_len - 1] = '\0';
328 container = "Domain Controllers";
329 obj_class = "computer";
335 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
336 "objectClass", obj_class);
337 msg->dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s",
338 cn_name, container, state->base_dn[database]);
340 return NT_STATUS_NO_MEMORY;
343 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
345 DEBUG(0,("Failed to create user record %s\n", 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", msg->dn));
352 return NT_STATUS_INTERNAL_DB_CORRUPTION;
359 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
360 struct samsync_ldb_state *state,
361 struct creds_CredentialState *creds,
362 enum netr_SamDatabaseID database,
363 struct netr_DELTA_ENUM *delta)
365 uint32_t rid = delta->delta_id_union.rid;
366 struct ldb_message **msgs;
368 const char *attrs[] = { NULL };
370 /* search for the user, by rid */
371 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
372 "(&(objectClass=user)(objectSid=%s))",
373 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
376 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
377 return NT_STATUS_INTERNAL_DB_CORRUPTION;
378 } else if (ret == 0) {
379 return NT_STATUS_NO_SUCH_USER;
380 } else if (ret > 1) {
381 DEBUG(0, ("More than one user with SID: %s\n",
382 dom_sid_string(mem_ctx,
383 dom_sid_add_rid(mem_ctx,
384 state->dom_sid[database],
386 return NT_STATUS_INTERNAL_DB_CORRUPTION;
389 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
391 DEBUG(0,("Failed to delete user record %s: %s\n", msgs[0]->dn, ldb_errstring(state->sam_ldb)));
392 return NT_STATUS_INTERNAL_DB_CORRUPTION;
398 static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
399 struct samsync_ldb_state *state,
400 struct creds_CredentialState *creds,
401 enum netr_SamDatabaseID database,
402 struct netr_DELTA_ENUM *delta)
404 uint32_t rid = delta->delta_id_union.rid;
405 struct netr_DELTA_GROUP *group = delta->delta_union.group;
406 const char *container, *obj_class;
409 struct ldb_message *msg;
410 struct ldb_message **msgs;
413 const char *attrs[] = { NULL };
415 msg = ldb_msg_new(mem_ctx);
417 return NT_STATUS_NO_MEMORY;
420 /* search for the group, by rid */
421 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
422 "(&(objectClass=group)(objectSid=%s))",
423 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
426 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
427 return NT_STATUS_INTERNAL_DB_CORRUPTION;
428 } else if (ret == 0) {
430 } else if (ret > 1) {
431 DEBUG(0, ("More than one group/alias with SID: %s\n",
432 dom_sid_string(mem_ctx,
433 dom_sid_add_rid(mem_ctx,
434 state->dom_sid[database],
436 return NT_STATUS_INTERNAL_DB_CORRUPTION;
438 msg->dn = talloc_steal(msg, msgs[0]->dn);
441 cn_name = group->group_name.string;
443 #define ADD_OR_DEL(type, attrib, field) do {\
444 if (group->field) { \
445 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
446 attrib, group->field); \
448 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
453 ADD_OR_DEL(string, "samAccountName", group_name.string);
455 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
456 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
457 return NT_STATUS_NO_MEMORY;
460 ADD_OR_DEL(string, "description", description.string);
468 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
469 "objectClass", obj_class);
470 msg->dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s",
471 cn_name, container, state->base_dn[database]);
473 return NT_STATUS_NO_MEMORY;
476 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
478 DEBUG(0,("Failed to create group record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
479 return NT_STATUS_INTERNAL_DB_CORRUPTION;
482 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
484 DEBUG(0,("Failed to modify group record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
485 return NT_STATUS_INTERNAL_DB_CORRUPTION;
492 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
493 struct samsync_ldb_state *state,
494 struct creds_CredentialState *creds,
495 enum netr_SamDatabaseID database,
496 struct netr_DELTA_ENUM *delta)
498 uint32_t rid = delta->delta_id_union.rid;
499 struct ldb_message **msgs;
501 const char *attrs[] = { NULL };
503 /* search for the group, by rid */
504 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
505 "(&(objectClass=group)(objectSid=%s))",
506 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
509 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
510 return NT_STATUS_INTERNAL_DB_CORRUPTION;
511 } else if (ret == 0) {
512 return NT_STATUS_NO_SUCH_GROUP;
513 } else if (ret > 1) {
514 DEBUG(0, ("More than one group/alias with SID: %s\n",
515 dom_sid_string(mem_ctx,
516 dom_sid_add_rid(mem_ctx,
517 state->dom_sid[database],
519 return NT_STATUS_INTERNAL_DB_CORRUPTION;
522 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
524 DEBUG(0,("Failed to delete group record %s: %s\n", msgs[0]->dn, ldb_errstring(state->sam_ldb)));
525 return NT_STATUS_INTERNAL_DB_CORRUPTION;
531 static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
532 struct samsync_ldb_state *state,
533 struct creds_CredentialState *creds,
534 enum netr_SamDatabaseID database,
535 struct netr_DELTA_ENUM *delta)
537 uint32_t rid = delta->delta_id_union.rid;
538 struct netr_DELTA_GROUP_MEMBER *group_member = delta->delta_union.group_member;
539 struct ldb_message *msg;
540 struct ldb_message **msgs;
542 const char *attrs[] = { NULL };
545 msg = ldb_msg_new(mem_ctx);
547 return NT_STATUS_NO_MEMORY;
550 /* search for the group, by rid */
551 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
552 "(&(objectClass=group)(objectSid=%s))",
553 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
556 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
557 return NT_STATUS_INTERNAL_DB_CORRUPTION;
558 } else if (ret == 0) {
559 return NT_STATUS_NO_SUCH_GROUP;
560 } else if (ret > 1) {
561 DEBUG(0, ("More than one group/alias with SID: %s\n",
562 dom_sid_string(mem_ctx,
563 dom_sid_add_rid(mem_ctx,
564 state->dom_sid[database],
566 return NT_STATUS_INTERNAL_DB_CORRUPTION;
568 msg->dn = talloc_steal(msg, msgs[0]->dn);
573 for (i=0; i<group_member->num_rids; i++) {
574 /* search for the group, by rid */
575 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
576 "(&(objectClass=user)(objectSid=%s))",
577 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], group_member->rids[i])));
580 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
581 return NT_STATUS_INTERNAL_DB_CORRUPTION;
582 } else if (ret == 0) {
583 return NT_STATUS_NO_SUCH_USER;
584 } else if (ret > 1) {
585 return NT_STATUS_INTERNAL_DB_CORRUPTION;
587 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", msgs[0]->dn);
593 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
595 DEBUG(0,("Failed to modify group record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
596 return NT_STATUS_INTERNAL_DB_CORRUPTION;
602 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
603 struct samsync_ldb_state *state,
604 struct creds_CredentialState *creds,
605 enum netr_SamDatabaseID database,
606 struct netr_DELTA_ENUM *delta)
608 uint32_t rid = delta->delta_id_union.rid;
609 struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
610 const char *container, *obj_class;
613 struct ldb_message *msg;
614 struct ldb_message **msgs;
617 const char *attrs[] = { NULL };
619 msg = ldb_msg_new(mem_ctx);
621 return NT_STATUS_NO_MEMORY;
624 /* search for the alias, by rid */
625 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
626 "(&(objectClass=group)(objectSid=%s))",
627 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
630 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
631 return NT_STATUS_INTERNAL_DB_CORRUPTION;
632 } else if (ret == 0) {
634 } else if (ret > 1) {
635 DEBUG(0, ("More than one group/alias with SID: %s\n",
636 dom_sid_string(mem_ctx,
637 dom_sid_add_rid(mem_ctx,
638 state->dom_sid[database],
640 return NT_STATUS_INTERNAL_DB_CORRUPTION;
642 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
645 cn_name = alias->alias_name.string;
647 #define ADD_OR_DEL(type, attrib, field) do {\
648 if (alias->field) { \
649 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
650 attrib, alias->field); \
652 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
657 ADD_OR_DEL(string, "samAccountName", alias_name.string);
659 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
660 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
661 return NT_STATUS_NO_MEMORY;
664 ADD_OR_DEL(string, "description", description.string);
668 samdb_msg_add_uint(state->sam_ldb, mem_ctx, msg, "groupType", 0x80000004);
674 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
675 "objectClass", obj_class);
676 msg->dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s",
677 cn_name, container, state->base_dn[database]);
679 return NT_STATUS_NO_MEMORY;
682 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
684 DEBUG(0,("Failed to create alias record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
685 return NT_STATUS_INTERNAL_DB_CORRUPTION;
688 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
690 DEBUG(0,("Failed to modify alias record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
691 return NT_STATUS_INTERNAL_DB_CORRUPTION;
698 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
699 struct samsync_ldb_state *state,
700 struct creds_CredentialState *creds,
701 enum netr_SamDatabaseID database,
702 struct netr_DELTA_ENUM *delta)
704 uint32_t rid = delta->delta_id_union.rid;
705 struct ldb_message **msgs;
707 const char *attrs[] = { NULL };
709 /* search for the alias, by rid */
710 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
711 "(&(objectClass=group)(objectSid=%s))",
712 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
715 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
716 return NT_STATUS_INTERNAL_DB_CORRUPTION;
717 } else if (ret == 0) {
718 return NT_STATUS_NO_SUCH_ALIAS;
719 } else if (ret > 1) {
720 return NT_STATUS_INTERNAL_DB_CORRUPTION;
723 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
725 DEBUG(0,("Failed to delete alias record %s: %s\n", msgs[0]->dn, ldb_errstring(state->sam_ldb)));
726 return NT_STATUS_INTERNAL_DB_CORRUPTION;
732 static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
733 struct samsync_ldb_state *state,
734 struct creds_CredentialState *creds,
735 enum netr_SamDatabaseID database,
736 struct netr_DELTA_ENUM *delta)
738 uint32_t rid = delta->delta_id_union.rid;
739 struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
740 struct ldb_message *msg;
741 struct ldb_message **msgs;
743 const char *attrs[] = { NULL };
746 msg = ldb_msg_new(mem_ctx);
748 return NT_STATUS_NO_MEMORY;
751 /* search for the alias, by rid */
752 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
753 "(&(objectClass=group)(objectSid=%s))",
754 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
757 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
758 return NT_STATUS_INTERNAL_DB_CORRUPTION;
759 } else if (ret == 0) {
760 return NT_STATUS_NO_SUCH_GROUP;
761 } else if (ret > 1) {
762 DEBUG(0, ("More than one group/alias with SID: %s\n",
763 dom_sid_string(mem_ctx,
764 dom_sid_add_rid(mem_ctx,
765 state->dom_sid[database],
767 return NT_STATUS_INTERNAL_DB_CORRUPTION;
769 msg->dn = talloc_steal(msg, msgs[0]->dn);
774 for (i=0; i<alias_member->sids.num_sids; i++) {
775 char *alias_member_dn;
776 /* search for members, in the top basedn (normal users are builtin aliases) */
777 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
779 ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid));
782 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
783 return NT_STATUS_INTERNAL_DB_CORRUPTION;
784 } else if (ret == 0) {
786 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
787 alias_member->sids.sids[i].sid,
789 if (!NT_STATUS_IS_OK(nt_status)) {
792 } else if (ret > 1) {
793 return NT_STATUS_INTERNAL_DB_CORRUPTION;
795 alias_member_dn = msgs[0]->dn;
797 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", alias_member_dn);
802 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
804 DEBUG(0,("Failed to modify group record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
805 return NT_STATUS_INTERNAL_DB_CORRUPTION;
811 static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
812 struct samsync_ldb_state *state,
813 struct creds_CredentialState *creds,
814 enum netr_SamDatabaseID database,
815 struct netr_DELTA_ENUM *delta)
817 struct dom_sid *sid = delta->delta_id_union.sid;
818 struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
820 struct ldb_message *msg;
821 struct ldb_message **msgs;
824 const char *attrs[] = { NULL };
827 msg = ldb_msg_new(mem_ctx);
829 return NT_STATUS_NO_MEMORY;
832 /* search for the account, by sid, in the top basedn */
833 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
834 "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, sid));
837 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
838 return NT_STATUS_INTERNAL_DB_CORRUPTION;
839 } else if (ret == 0) {
841 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
844 privilage_dn = talloc_steal(msg, privilage_dn);
845 if (!NT_STATUS_IS_OK(nt_status)) {
848 } else if (ret > 1) {
849 DEBUG(0, ("More than one account with SID: %s\n",
850 dom_sid_string(mem_ctx, sid)));
851 return NT_STATUS_INTERNAL_DB_CORRUPTION;
853 privilage_dn = talloc_steal(msg, msgs[0]->dn);
856 msg->dn = privilage_dn;
858 for (i=0; i< account->privilege_entries; i++) {
859 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "privilage",
860 account->privilege_name[i].string);
863 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
865 DEBUG(0,("Failed to modify privilage record %s\n", msg->dn));
866 return NT_STATUS_INTERNAL_DB_CORRUPTION;
872 static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
873 struct samsync_ldb_state *state,
874 struct creds_CredentialState *creds,
875 enum netr_SamDatabaseID database,
876 struct netr_DELTA_ENUM *delta)
878 struct dom_sid *sid = delta->delta_id_union.sid;
880 struct ldb_message *msg;
881 struct ldb_message **msgs;
883 const char *attrs[] = { NULL };
885 msg = ldb_msg_new(mem_ctx);
887 return NT_STATUS_NO_MEMORY;
890 /* search for the account, by sid, in the top basedn */
891 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
893 ldap_encode_ndr_dom_sid(mem_ctx, sid));
896 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
897 return NT_STATUS_INTERNAL_DB_CORRUPTION;
898 } else if (ret == 0) {
899 return NT_STATUS_NO_SUCH_USER;
900 } else if (ret > 1) {
901 DEBUG(0, ("More than one account with SID: %s\n",
902 dom_sid_string(mem_ctx, sid)));
903 return NT_STATUS_INTERNAL_DB_CORRUPTION;
905 msg->dn = talloc_steal(msg, msgs[0]->dn);
908 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
911 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
913 DEBUG(0,("Failed to modify privilage record %s\n", msg->dn));
914 return NT_STATUS_INTERNAL_DB_CORRUPTION;
920 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,
922 struct creds_CredentialState *creds,
923 enum netr_SamDatabaseID database,
924 struct netr_DELTA_ENUM *delta,
927 NTSTATUS nt_status = NT_STATUS_OK;
928 struct samsync_ldb_state *state = private;
930 *error_string = NULL;
931 switch (delta->delta_type) {
932 case NETR_DELTA_DOMAIN:
934 nt_status = samsync_ldb_handle_domain(mem_ctx,
941 case NETR_DELTA_USER:
943 nt_status = samsync_ldb_handle_user(mem_ctx,
950 case NETR_DELTA_DELETE_USER:
952 nt_status = samsync_ldb_delete_user(mem_ctx,
959 case NETR_DELTA_GROUP:
961 nt_status = samsync_ldb_handle_group(mem_ctx,
968 case NETR_DELTA_DELETE_GROUP:
970 nt_status = samsync_ldb_delete_group(mem_ctx,
977 case NETR_DELTA_GROUP_MEMBER:
979 nt_status = samsync_ldb_handle_group_member(mem_ctx,
986 case NETR_DELTA_ALIAS:
988 nt_status = samsync_ldb_handle_alias(mem_ctx,
995 case NETR_DELTA_DELETE_ALIAS:
997 nt_status = samsync_ldb_delete_alias(mem_ctx,
1004 case NETR_DELTA_ALIAS_MEMBER:
1006 nt_status = samsync_ldb_handle_alias_member(mem_ctx,
1013 case NETR_DELTA_ACCOUNT:
1015 nt_status = samsync_ldb_handle_account(mem_ctx,
1022 case NETR_DELTA_DELETE_ACCOUNT:
1024 nt_status = samsync_ldb_delete_account(mem_ctx,
1032 /* Can't dump them all right now */
1038 static NTSTATUS libnet_samsync_ldb_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1041 struct libnet_SamSync r2;
1042 struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
1045 return NT_STATUS_NO_MEMORY;
1048 state->secrets = NULL;
1049 state->trusted_domains = NULL;
1051 state->sam_ldb = samdb_connect(state);
1055 r2.error_string = NULL;
1056 r2.delta_fn = libnet_samsync_ldb_fn;
1058 r2.machine_account = NULL; /* TODO: Create a machine account, fill this in, and the delete it */
1059 nt_status = libnet_SamSync_netlogon(ctx, state, &r2);
1060 r->error_string = r2.error_string;
1062 if (!NT_STATUS_IS_OK(nt_status)) {
1072 static NTSTATUS libnet_samsync_ldb_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1075 struct libnet_samsync_ldb r2;
1076 r2.level = LIBNET_SAMSYNC_LDB_NETLOGON;
1077 r2.error_string = NULL;
1078 nt_status = libnet_samsync_ldb(ctx, mem_ctx, &r2);
1079 r->error_string = r2.error_string;
1084 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1087 case LIBNET_SAMSYNC_LDB_GENERIC:
1088 return libnet_samsync_ldb_generic(ctx, mem_ctx, r);
1089 case LIBNET_SAMSYNC_LDB_NETLOGON:
1090 return libnet_samsync_ldb_netlogon(ctx, mem_ctx, r);
1093 return NT_STATUS_INVALID_LEVEL;