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 "libcli/ldap/ldap.h"
32 #include "lib/ldb/include/ldb.h"
33 #include "dsdb/samdb/samdb.h"
34 #include "auth/auth.h"
36 struct samsync_ldb_secret {
37 struct samsync_ldb_secret *prev, *next;
43 struct samsync_ldb_trusted_domain {
44 struct samsync_ldb_trusted_domain *prev, *next;
49 struct samsync_ldb_state {
50 struct dom_sid *dom_sid[3];
51 struct ldb_context *sam_ldb;
52 struct ldb_dn *base_dn[3];
53 struct samsync_ldb_secret *secrets;
54 struct samsync_ldb_trusted_domain *trusted_domains;
57 static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,
58 struct samsync_ldb_state *state,
60 struct ldb_dn **fsp_dn)
62 const char *sidstr = dom_sid_string(mem_ctx, sid);
63 /* We assume that ForeignSecurityPrincipals are under the BASEDN of the main domain */
64 struct ldb_dn *basedn = samdb_search_dn(state->sam_ldb, mem_ctx,
65 state->base_dn[SAM_DATABASE_DOMAIN],
66 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
67 struct ldb_message *msg;
71 return NT_STATUS_NO_MEMORY;
75 DEBUG(0, ("Failed to find DN for "
76 "ForeignSecurityPrincipal container\n"));
77 return NT_STATUS_INTERNAL_DB_CORRUPTION;
80 msg = ldb_msg_new(mem_ctx);
82 return NT_STATUS_NO_MEMORY;
85 /* add core elements to the ldb_message for the alias */
86 msg->dn = ldb_dn_build_child(mem_ctx, "CN", sidstr, basedn);
88 return NT_STATUS_NO_MEMORY;
90 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
92 "foreignSecurityPrincipal");
96 /* create the alias */
97 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
99 DEBUG(0,("Failed to create foreignSecurityPrincipal "
101 ldb_dn_linearize(mem_ctx, msg->dn),
102 ldb_errstring(state->sam_ldb)));
103 return NT_STATUS_INTERNAL_DB_CORRUPTION;
108 static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
109 struct samsync_ldb_state *state,
110 struct creds_CredentialState *creds,
111 enum netr_SamDatabaseID database,
112 struct netr_DELTA_ENUM *delta)
114 struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;
115 const char *domain_name = domain->domain_name.string;
116 struct ldb_message *msg;
119 if (database == SAM_DATABASE_DOMAIN) {
120 const char *domain_attrs[] = {"nETBIOSName", "nCName", NULL};
121 struct ldb_message **msgs_domain;
124 ret_domain = gendb_search(state->sam_ldb, mem_ctx, NULL, &msgs_domain, domain_attrs,
125 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
127 if (ret_domain == -1) {
128 return NT_STATUS_INTERNAL_DB_CORRUPTION;
131 if (ret_domain != 1) {
132 return NT_STATUS_NO_SUCH_DOMAIN;
135 state->base_dn[database] = samdb_result_dn(state, msgs_domain[0], "nCName", NULL);
137 state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state,
138 state->base_dn[database],
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 "distinguishedName", "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;
289 /* Passwords. Ensure there is no plaintext stored against
290 * this entry, as we only have hashes */
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 = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
338 "CN=%s, CN=%s", cn_name, container);
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",
346 ldb_dn_linearize(mem_ctx, msg->dn)));
347 return NT_STATUS_INTERNAL_DB_CORRUPTION;
350 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
352 DEBUG(0,("Failed to modify user record %s\n",
353 ldb_dn_linearize(mem_ctx, msg->dn)));
354 return NT_STATUS_INTERNAL_DB_CORRUPTION;
361 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
362 struct samsync_ldb_state *state,
363 struct creds_CredentialState *creds,
364 enum netr_SamDatabaseID database,
365 struct netr_DELTA_ENUM *delta)
367 uint32_t rid = delta->delta_id_union.rid;
368 struct ldb_message **msgs;
370 const char *attrs[] = { NULL };
372 /* search for the user, by rid */
373 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
374 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
375 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
378 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
379 return NT_STATUS_INTERNAL_DB_CORRUPTION;
380 } else if (ret == 0) {
381 return NT_STATUS_NO_SUCH_USER;
382 } else if (ret > 1) {
383 DEBUG(0, ("More than one user with SID: %s\n",
384 dom_sid_string(mem_ctx,
385 dom_sid_add_rid(mem_ctx,
386 state->dom_sid[database],
388 return NT_STATUS_INTERNAL_DB_CORRUPTION;
391 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
393 DEBUG(0,("Failed to delete user record %s: %s\n",
394 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
395 ldb_errstring(state->sam_ldb)));
396 return NT_STATUS_INTERNAL_DB_CORRUPTION;
402 static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
403 struct samsync_ldb_state *state,
404 struct creds_CredentialState *creds,
405 enum netr_SamDatabaseID database,
406 struct netr_DELTA_ENUM *delta)
408 uint32_t rid = delta->delta_id_union.rid;
409 struct netr_DELTA_GROUP *group = delta->delta_union.group;
410 const char *container, *obj_class;
413 struct ldb_message *msg;
414 struct ldb_message **msgs;
417 const char *attrs[] = { NULL };
419 msg = ldb_msg_new(mem_ctx);
421 return NT_STATUS_NO_MEMORY;
424 /* search for the group, by rid */
425 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
426 "(&(objectClass=group)(objectSid=%s))",
427 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
430 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
431 return NT_STATUS_INTERNAL_DB_CORRUPTION;
432 } else if (ret == 0) {
434 } else if (ret > 1) {
435 DEBUG(0, ("More than one group/alias with SID: %s\n",
436 dom_sid_string(mem_ctx,
437 dom_sid_add_rid(mem_ctx,
438 state->dom_sid[database],
440 return NT_STATUS_INTERNAL_DB_CORRUPTION;
442 msg->dn = talloc_steal(msg, msgs[0]->dn);
445 cn_name = group->group_name.string;
447 #define ADD_OR_DEL(type, attrib, field) do {\
448 if (group->field) { \
449 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
450 attrib, group->field); \
452 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
457 ADD_OR_DEL(string, "samAccountName", group_name.string);
459 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
460 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
461 return NT_STATUS_NO_MEMORY;
464 ADD_OR_DEL(string, "description", description.string);
472 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
473 "objectClass", obj_class);
474 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
475 "CN=%s, CN=%s", cn_name, container);
477 return NT_STATUS_NO_MEMORY;
480 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
482 DEBUG(0,("Failed to create group record %s: %s\n",
483 ldb_dn_linearize(mem_ctx, msg->dn),
484 ldb_errstring(state->sam_ldb)));
485 return NT_STATUS_INTERNAL_DB_CORRUPTION;
488 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
490 DEBUG(0,("Failed to modify group record %s: %s\n",
491 ldb_dn_linearize(mem_ctx, msg->dn),
492 ldb_errstring(state->sam_ldb)));
493 return NT_STATUS_INTERNAL_DB_CORRUPTION;
500 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
501 struct samsync_ldb_state *state,
502 struct creds_CredentialState *creds,
503 enum netr_SamDatabaseID database,
504 struct netr_DELTA_ENUM *delta)
506 uint32_t rid = delta->delta_id_union.rid;
507 struct ldb_message **msgs;
509 const char *attrs[] = { NULL };
511 /* search for the group, by rid */
512 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
513 "(&(objectClass=group)(objectSid=%s))",
514 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
517 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
518 return NT_STATUS_INTERNAL_DB_CORRUPTION;
519 } else if (ret == 0) {
520 return NT_STATUS_NO_SUCH_GROUP;
521 } else if (ret > 1) {
522 DEBUG(0, ("More than one group/alias with SID: %s\n",
523 dom_sid_string(mem_ctx,
524 dom_sid_add_rid(mem_ctx,
525 state->dom_sid[database],
527 return NT_STATUS_INTERNAL_DB_CORRUPTION;
530 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
532 DEBUG(0,("Failed to delete group record %s: %s\n",
533 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
534 ldb_errstring(state->sam_ldb)));
535 return NT_STATUS_INTERNAL_DB_CORRUPTION;
541 static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
542 struct samsync_ldb_state *state,
543 struct creds_CredentialState *creds,
544 enum netr_SamDatabaseID database,
545 struct netr_DELTA_ENUM *delta)
547 uint32_t rid = delta->delta_id_union.rid;
548 struct netr_DELTA_GROUP_MEMBER *group_member = delta->delta_union.group_member;
549 struct ldb_message *msg;
550 struct ldb_message **msgs;
552 const char *attrs[] = { NULL };
555 msg = ldb_msg_new(mem_ctx);
557 return NT_STATUS_NO_MEMORY;
560 /* search for the group, by rid */
561 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
562 "(&(objectClass=group)(objectSid=%s))",
563 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
566 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
567 return NT_STATUS_INTERNAL_DB_CORRUPTION;
568 } else if (ret == 0) {
569 return NT_STATUS_NO_SUCH_GROUP;
570 } else if (ret > 1) {
571 DEBUG(0, ("More than one group/alias with SID: %s\n",
572 dom_sid_string(mem_ctx,
573 dom_sid_add_rid(mem_ctx,
574 state->dom_sid[database],
576 return NT_STATUS_INTERNAL_DB_CORRUPTION;
578 msg->dn = talloc_steal(msg, msgs[0]->dn);
583 for (i=0; i<group_member->num_rids; i++) {
584 /* search for the group, by rid */
585 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
586 "(&(objectClass=user)(objectSid=%s))",
587 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], group_member->rids[i])));
590 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
591 return NT_STATUS_INTERNAL_DB_CORRUPTION;
592 } else if (ret == 0) {
593 return NT_STATUS_NO_SUCH_USER;
594 } else if (ret > 1) {
595 return NT_STATUS_INTERNAL_DB_CORRUPTION;
597 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, msgs[0]->dn));
603 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
605 DEBUG(0,("Failed to modify group record %s: %s\n",
606 ldb_dn_linearize(mem_ctx, msg->dn),
607 ldb_errstring(state->sam_ldb)));
608 return NT_STATUS_INTERNAL_DB_CORRUPTION;
614 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
615 struct samsync_ldb_state *state,
616 struct creds_CredentialState *creds,
617 enum netr_SamDatabaseID database,
618 struct netr_DELTA_ENUM *delta)
620 uint32_t rid = delta->delta_id_union.rid;
621 struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
622 const char *container, *obj_class;
625 struct ldb_message *msg;
626 struct ldb_message **msgs;
629 const char *attrs[] = { NULL };
631 msg = ldb_msg_new(mem_ctx);
633 return NT_STATUS_NO_MEMORY;
636 /* search for the alias, by rid */
637 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
638 "(&(objectClass=group)(objectSid=%s))",
639 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
642 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
643 return NT_STATUS_INTERNAL_DB_CORRUPTION;
644 } else if (ret == 0) {
646 } else if (ret > 1) {
647 DEBUG(0, ("More than one group/alias with SID: %s\n",
648 dom_sid_string(mem_ctx,
649 dom_sid_add_rid(mem_ctx,
650 state->dom_sid[database],
652 return NT_STATUS_INTERNAL_DB_CORRUPTION;
654 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
657 cn_name = alias->alias_name.string;
659 #define ADD_OR_DEL(type, attrib, field) do {\
660 if (alias->field) { \
661 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
662 attrib, alias->field); \
664 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
669 ADD_OR_DEL(string, "samAccountName", alias_name.string);
671 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
672 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
673 return NT_STATUS_NO_MEMORY;
676 ADD_OR_DEL(string, "description", description.string);
680 samdb_msg_add_uint(state->sam_ldb, mem_ctx, msg, "groupType", 0x80000004);
686 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
687 "objectClass", obj_class);
688 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
689 "CN=%s, CN=%s", cn_name, container);
691 return NT_STATUS_NO_MEMORY;
694 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
696 DEBUG(0,("Failed to create alias record %s: %s\n",
697 ldb_dn_linearize(mem_ctx, msg->dn),
698 ldb_errstring(state->sam_ldb)));
699 return NT_STATUS_INTERNAL_DB_CORRUPTION;
702 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
704 DEBUG(0,("Failed to modify alias record %s: %s\n",
705 ldb_dn_linearize(mem_ctx, msg->dn),
706 ldb_errstring(state->sam_ldb)));
707 return NT_STATUS_INTERNAL_DB_CORRUPTION;
714 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
715 struct samsync_ldb_state *state,
716 struct creds_CredentialState *creds,
717 enum netr_SamDatabaseID database,
718 struct netr_DELTA_ENUM *delta)
720 uint32_t rid = delta->delta_id_union.rid;
721 struct ldb_message **msgs;
723 const char *attrs[] = { NULL };
725 /* search for the alias, by rid */
726 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
727 "(&(objectClass=group)(objectSid=%s))",
728 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
731 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
732 return NT_STATUS_INTERNAL_DB_CORRUPTION;
733 } else if (ret == 0) {
734 return NT_STATUS_NO_SUCH_ALIAS;
735 } else if (ret > 1) {
736 return NT_STATUS_INTERNAL_DB_CORRUPTION;
739 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
741 DEBUG(0,("Failed to delete alias record %s: %s\n",
742 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
743 ldb_errstring(state->sam_ldb)));
744 return NT_STATUS_INTERNAL_DB_CORRUPTION;
750 static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
751 struct samsync_ldb_state *state,
752 struct creds_CredentialState *creds,
753 enum netr_SamDatabaseID database,
754 struct netr_DELTA_ENUM *delta)
756 uint32_t rid = delta->delta_id_union.rid;
757 struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
758 struct ldb_message *msg;
759 struct ldb_message **msgs;
761 const char *attrs[] = { NULL };
764 msg = ldb_msg_new(mem_ctx);
766 return NT_STATUS_NO_MEMORY;
769 /* search for the alias, by rid */
770 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
771 "(&(objectClass=group)(objectSid=%s))",
772 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
775 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
776 return NT_STATUS_INTERNAL_DB_CORRUPTION;
777 } else if (ret == 0) {
778 return NT_STATUS_NO_SUCH_GROUP;
779 } else if (ret > 1) {
780 DEBUG(0, ("More than one group/alias with SID: %s\n",
781 dom_sid_string(mem_ctx,
782 dom_sid_add_rid(mem_ctx,
783 state->dom_sid[database],
785 return NT_STATUS_INTERNAL_DB_CORRUPTION;
787 msg->dn = talloc_steal(msg, msgs[0]->dn);
792 for (i=0; i<alias_member->sids.num_sids; i++) {
793 struct ldb_dn *alias_member_dn;
794 /* search for members, in the top basedn (normal users are builtin aliases) */
795 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
797 ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid));
800 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
801 return NT_STATUS_INTERNAL_DB_CORRUPTION;
802 } else if (ret == 0) {
804 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
805 alias_member->sids.sids[i].sid,
807 if (!NT_STATUS_IS_OK(nt_status)) {
810 } else if (ret > 1) {
811 return NT_STATUS_INTERNAL_DB_CORRUPTION;
813 alias_member_dn = msgs[0]->dn;
815 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, alias_member_dn));
820 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
822 DEBUG(0,("Failed to modify group record %s: %s\n",
823 ldb_dn_linearize(mem_ctx, msg->dn),
824 ldb_errstring(state->sam_ldb)));
825 return NT_STATUS_INTERNAL_DB_CORRUPTION;
831 static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
832 struct samsync_ldb_state *state,
833 struct creds_CredentialState *creds,
834 enum netr_SamDatabaseID database,
835 struct netr_DELTA_ENUM *delta)
837 struct dom_sid *sid = delta->delta_id_union.sid;
838 struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
840 struct ldb_message *msg;
841 struct ldb_message **msgs;
842 struct ldb_dn *privilege_dn;
844 const char *attrs[] = { NULL };
847 msg = ldb_msg_new(mem_ctx);
849 return NT_STATUS_NO_MEMORY;
852 /* search for the account, by sid, in the top basedn */
853 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
854 "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, sid));
857 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
858 return NT_STATUS_INTERNAL_DB_CORRUPTION;
859 } else if (ret == 0) {
861 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
864 privilege_dn = talloc_steal(msg, privilege_dn);
865 if (!NT_STATUS_IS_OK(nt_status)) {
868 } else if (ret > 1) {
869 DEBUG(0, ("More than one account with SID: %s\n",
870 dom_sid_string(mem_ctx, sid)));
871 return NT_STATUS_INTERNAL_DB_CORRUPTION;
873 privilege_dn = talloc_steal(msg, msgs[0]->dn);
876 msg->dn = privilege_dn;
878 for (i=0; i< account->privilege_entries; i++) {
879 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "privilege",
880 account->privilege_name[i].string);
883 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
885 DEBUG(0,("Failed to modify privilege record %s\n",
886 ldb_dn_linearize(mem_ctx, msg->dn)));
887 return NT_STATUS_INTERNAL_DB_CORRUPTION;
893 static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
894 struct samsync_ldb_state *state,
895 struct creds_CredentialState *creds,
896 enum netr_SamDatabaseID database,
897 struct netr_DELTA_ENUM *delta)
899 struct dom_sid *sid = delta->delta_id_union.sid;
901 struct ldb_message *msg;
902 struct ldb_message **msgs;
904 const char *attrs[] = { NULL };
906 msg = ldb_msg_new(mem_ctx);
908 return NT_STATUS_NO_MEMORY;
911 /* search for the account, by sid, in the top basedn */
912 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
914 ldap_encode_ndr_dom_sid(mem_ctx, sid));
917 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
918 return NT_STATUS_INTERNAL_DB_CORRUPTION;
919 } else if (ret == 0) {
920 return NT_STATUS_NO_SUCH_USER;
921 } else if (ret > 1) {
922 DEBUG(0, ("More than one account with SID: %s\n",
923 dom_sid_string(mem_ctx, sid)));
924 return NT_STATUS_INTERNAL_DB_CORRUPTION;
926 msg->dn = talloc_steal(msg, msgs[0]->dn);
929 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
932 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
934 DEBUG(0,("Failed to modify privilege record %s\n",
935 ldb_dn_linearize(mem_ctx, msg->dn)));
936 return NT_STATUS_INTERNAL_DB_CORRUPTION;
942 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,
944 struct creds_CredentialState *creds,
945 enum netr_SamDatabaseID database,
946 struct netr_DELTA_ENUM *delta,
949 NTSTATUS nt_status = NT_STATUS_OK;
950 struct samsync_ldb_state *state = private;
952 *error_string = NULL;
953 switch (delta->delta_type) {
954 case NETR_DELTA_DOMAIN:
956 nt_status = samsync_ldb_handle_domain(mem_ctx,
963 case NETR_DELTA_USER:
965 nt_status = samsync_ldb_handle_user(mem_ctx,
972 case NETR_DELTA_DELETE_USER:
974 nt_status = samsync_ldb_delete_user(mem_ctx,
981 case NETR_DELTA_GROUP:
983 nt_status = samsync_ldb_handle_group(mem_ctx,
990 case NETR_DELTA_DELETE_GROUP:
992 nt_status = samsync_ldb_delete_group(mem_ctx,
999 case NETR_DELTA_GROUP_MEMBER:
1001 nt_status = samsync_ldb_handle_group_member(mem_ctx,
1008 case NETR_DELTA_ALIAS:
1010 nt_status = samsync_ldb_handle_alias(mem_ctx,
1017 case NETR_DELTA_DELETE_ALIAS:
1019 nt_status = samsync_ldb_delete_alias(mem_ctx,
1026 case NETR_DELTA_ALIAS_MEMBER:
1028 nt_status = samsync_ldb_handle_alias_member(mem_ctx,
1035 case NETR_DELTA_ACCOUNT:
1037 nt_status = samsync_ldb_handle_account(mem_ctx,
1044 case NETR_DELTA_DELETE_ACCOUNT:
1046 nt_status = samsync_ldb_delete_account(mem_ctx,
1054 /* Can't dump them all right now */
1060 static NTSTATUS libnet_samsync_ldb_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1063 struct libnet_SamSync r2;
1064 struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
1067 return NT_STATUS_NO_MEMORY;
1070 state->secrets = NULL;
1071 state->trusted_domains = NULL;
1073 state->sam_ldb = samdb_connect(state, system_session(state));
1075 r2.error_string = NULL;
1076 r2.delta_fn = libnet_samsync_ldb_fn;
1078 r2.machine_account = NULL; /* TODO: Create a machine account, fill this in, and the delete it */
1079 nt_status = libnet_SamSync_netlogon(ctx, state, &r2);
1080 r->error_string = r2.error_string;
1082 if (!NT_STATUS_IS_OK(nt_status)) {
1092 static NTSTATUS libnet_samsync_ldb_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1095 struct libnet_samsync_ldb r2;
1096 r2.level = LIBNET_SAMSYNC_LDB_NETLOGON;
1097 r2.error_string = NULL;
1098 nt_status = libnet_samsync_ldb(ctx, mem_ctx, &r2);
1099 r->error_string = r2.error_string;
1104 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1107 case LIBNET_SAMSYNC_LDB_GENERIC:
1108 return libnet_samsync_ldb_generic(ctx, mem_ctx, r);
1109 case LIBNET_SAMSYNC_LDB_NETLOGON:
1110 return libnet_samsync_ldb_netlogon(ctx, mem_ctx, r);
1113 return NT_STATUS_INVALID_LEVEL;