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;
121 ret_domain = gendb_search(state->sam_ldb, mem_ctx, NULL, &msgs_domain, domain_attrs,
122 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
124 if (ret_domain == -1) {
125 return NT_STATUS_INTERNAL_DB_CORRUPTION;
128 if (ret_domain != 1) {
129 return NT_STATUS_NO_SUCH_DOMAIN;
132 state->base_dn[database] = samdb_result_dn(state, msgs_domain[0], "nCName", NULL);
134 state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state,
135 state->base_dn[database],
137 } else if (database == SAM_DATABASE_BUILTIN) {
138 /* work out the builtin_dn - useful for so many calls its worth
140 const char *dnstring = samdb_search_string(state->sam_ldb, mem_ctx, NULL,
141 "distinguishedName", "objectClass=builtinDomain");
142 state->base_dn[database] = ldb_dn_explode(state, dnstring);
143 state->dom_sid[database] = dom_sid_parse_talloc(state, SID_BUILTIN);
146 return NT_STATUS_INVALID_PARAMETER;
149 msg = ldb_msg_new(mem_ctx);
151 return NT_STATUS_NO_MEMORY;
154 msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
156 return NT_STATUS_NO_MEMORY;
159 samdb_msg_add_string(state->sam_ldb, mem_ctx,
160 msg, "oEMInformation", domain->comment.string);
162 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
163 msg, "forceLogoff", domain->force_logoff_time);
165 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
166 msg, "minPwdLen", domain->min_password_length);
168 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
169 msg, "maxPwdAge", domain->max_password_age);
171 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
172 msg, "minPwdAge", domain->min_password_age);
174 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
175 msg, "pwdHistoryLength", domain->password_history_length);
177 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
178 msg, "modifiedCount",
179 domain->sequence_num);
181 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
182 msg, "creationTime", domain->domain_create_time);
184 /* TODO: Account lockout, password properties */
186 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
189 return NT_STATUS_INTERNAL_ERROR;
194 static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
195 struct samsync_ldb_state *state,
196 struct creds_CredentialState *creds,
197 enum netr_SamDatabaseID database,
198 struct netr_DELTA_ENUM *delta)
200 uint32_t rid = delta->delta_id_union.rid;
201 struct netr_DELTA_USER *user = delta->delta_union.user;
202 const char *container, *obj_class;
206 struct ldb_message *msg;
207 struct ldb_message **msgs;
211 const char *attrs[] = { NULL };
213 msg = ldb_msg_new(mem_ctx);
215 return NT_STATUS_NO_MEMORY;
218 /* search for the user, by rid */
219 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
220 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
221 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
224 return NT_STATUS_INTERNAL_DB_CORRUPTION;
225 } else if (ret == 0) {
227 } else if (ret > 1) {
228 DEBUG(0, ("More than one user with SID: %s\n",
229 dom_sid_string(mem_ctx,
230 dom_sid_add_rid(mem_ctx,
231 state->dom_sid[database],
233 return NT_STATUS_INTERNAL_DB_CORRUPTION;
235 msg->dn = talloc_steal(msg, msgs[0]->dn);
239 cn_name = talloc_strdup(mem_ctx, user->account_name.string);
240 NT_STATUS_HAVE_NO_MEMORY(cn_name);
241 cn_name_len = strlen(cn_name);
243 #define ADD_OR_DEL(type, attrib, field) do {\
245 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
246 attrib, user->field); \
248 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
253 ADD_OR_DEL(string, "samAccountName", account_name.string);
254 ADD_OR_DEL(string, "displayName", full_name.string);
256 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
257 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
258 return NT_STATUS_NO_MEMORY;
261 ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
262 ADD_OR_DEL(string, "homeDirectory", home_directory.string);
263 ADD_OR_DEL(string, "homeDrive", home_drive.string);
264 ADD_OR_DEL(string, "scriptPath", logon_script.string);
265 ADD_OR_DEL(string, "description", description.string);
266 ADD_OR_DEL(string, "userWorkstations", workstations.string);
268 ADD_OR_DEL(uint64, "lastLogon", last_logon);
269 ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
271 if (samdb_msg_add_logon_hours(state->sam_ldb, mem_ctx, msg, "logonHours", &user->logon_hours) != 0) {
272 return NT_STATUS_NO_MEMORY;
275 ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
276 ADD_OR_DEL(uint, "logonCount", logon_count);
278 ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
279 ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
281 if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg,
282 "userAccountControl", user->acct_flags) != 0) {
283 return NT_STATUS_NO_MEMORY;
286 /* Passwords. Ensure there is no plaintext stored against
287 * this entry, as we only have hashes */
288 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
290 if (user->lm_password_present) {
291 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
292 "lmPwdHash", &user->lmpassword);
294 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
297 if (user->nt_password_present) {
298 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
299 "ntPwdHash", &user->ntpassword);
301 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
305 ADD_OR_DEL(string, "comment", comment.string);
306 ADD_OR_DEL(string, "userParameters", parameters.string);
307 ADD_OR_DEL(uint, "countryCode", country_code);
308 ADD_OR_DEL(uint, "codePage", code_page);
310 ADD_OR_DEL(string, "profilePath", profile_path.string);
314 acb = user->acct_flags;
315 if (acb & (ACB_WSTRUST)) {
316 cn_name[cn_name_len - 1] = '\0';
317 container = "Computers";
318 obj_class = "computer";
320 } else if (acb & ACB_SVRTRUST) {
321 if (cn_name[cn_name_len - 1] != '$') {
322 return NT_STATUS_FOOBAR;
324 cn_name[cn_name_len - 1] = '\0';
325 container = "Domain Controllers";
326 obj_class = "computer";
332 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
333 "objectClass", obj_class);
334 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
335 "CN=%s, CN=%s", cn_name, container);
337 return NT_STATUS_NO_MEMORY;
340 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
342 DEBUG(0,("Failed to create user record %s\n",
343 ldb_dn_linearize(mem_ctx, msg->dn)));
344 return NT_STATUS_INTERNAL_DB_CORRUPTION;
347 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
349 DEBUG(0,("Failed to modify user record %s\n",
350 ldb_dn_linearize(mem_ctx, msg->dn)));
351 return NT_STATUS_INTERNAL_DB_CORRUPTION;
358 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
359 struct samsync_ldb_state *state,
360 struct creds_CredentialState *creds,
361 enum netr_SamDatabaseID database,
362 struct netr_DELTA_ENUM *delta)
364 uint32_t rid = delta->delta_id_union.rid;
365 struct ldb_message **msgs;
367 const char *attrs[] = { NULL };
369 /* search for the user, by rid */
370 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
371 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
372 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
375 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
376 return NT_STATUS_INTERNAL_DB_CORRUPTION;
377 } else if (ret == 0) {
378 return NT_STATUS_NO_SUCH_USER;
379 } else if (ret > 1) {
380 DEBUG(0, ("More than one user with SID: %s\n",
381 dom_sid_string(mem_ctx,
382 dom_sid_add_rid(mem_ctx,
383 state->dom_sid[database],
385 return NT_STATUS_INTERNAL_DB_CORRUPTION;
388 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
390 DEBUG(0,("Failed to delete user record %s: %s\n",
391 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
392 ldb_errstring(state->sam_ldb)));
393 return NT_STATUS_INTERNAL_DB_CORRUPTION;
399 static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
400 struct samsync_ldb_state *state,
401 struct creds_CredentialState *creds,
402 enum netr_SamDatabaseID database,
403 struct netr_DELTA_ENUM *delta)
405 uint32_t rid = delta->delta_id_union.rid;
406 struct netr_DELTA_GROUP *group = delta->delta_union.group;
407 const char *container, *obj_class;
410 struct ldb_message *msg;
411 struct ldb_message **msgs;
414 const char *attrs[] = { NULL };
416 msg = ldb_msg_new(mem_ctx);
418 return NT_STATUS_NO_MEMORY;
421 /* search for the group, by rid */
422 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
423 "(&(objectClass=group)(objectSid=%s))",
424 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
427 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
428 return NT_STATUS_INTERNAL_DB_CORRUPTION;
429 } else if (ret == 0) {
431 } else if (ret > 1) {
432 DEBUG(0, ("More than one group/alias with SID: %s\n",
433 dom_sid_string(mem_ctx,
434 dom_sid_add_rid(mem_ctx,
435 state->dom_sid[database],
437 return NT_STATUS_INTERNAL_DB_CORRUPTION;
439 msg->dn = talloc_steal(msg, msgs[0]->dn);
442 cn_name = group->group_name.string;
444 #define ADD_OR_DEL(type, attrib, field) do {\
445 if (group->field) { \
446 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
447 attrib, group->field); \
449 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
454 ADD_OR_DEL(string, "samAccountName", group_name.string);
456 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
457 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
458 return NT_STATUS_NO_MEMORY;
461 ADD_OR_DEL(string, "description", description.string);
469 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
470 "objectClass", obj_class);
471 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
472 "CN=%s, CN=%s", cn_name, container);
474 return NT_STATUS_NO_MEMORY;
477 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
479 DEBUG(0,("Failed to create group record %s: %s\n",
480 ldb_dn_linearize(mem_ctx, msg->dn),
481 ldb_errstring(state->sam_ldb)));
482 return NT_STATUS_INTERNAL_DB_CORRUPTION;
485 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
487 DEBUG(0,("Failed to modify group record %s: %s\n",
488 ldb_dn_linearize(mem_ctx, msg->dn),
489 ldb_errstring(state->sam_ldb)));
490 return NT_STATUS_INTERNAL_DB_CORRUPTION;
497 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
498 struct samsync_ldb_state *state,
499 struct creds_CredentialState *creds,
500 enum netr_SamDatabaseID database,
501 struct netr_DELTA_ENUM *delta)
503 uint32_t rid = delta->delta_id_union.rid;
504 struct ldb_message **msgs;
506 const char *attrs[] = { NULL };
508 /* search for the group, by rid */
509 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
510 "(&(objectClass=group)(objectSid=%s))",
511 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
514 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
515 return NT_STATUS_INTERNAL_DB_CORRUPTION;
516 } else if (ret == 0) {
517 return NT_STATUS_NO_SUCH_GROUP;
518 } else if (ret > 1) {
519 DEBUG(0, ("More than one group/alias with SID: %s\n",
520 dom_sid_string(mem_ctx,
521 dom_sid_add_rid(mem_ctx,
522 state->dom_sid[database],
524 return NT_STATUS_INTERNAL_DB_CORRUPTION;
527 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
529 DEBUG(0,("Failed to delete group record %s: %s\n",
530 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
531 ldb_errstring(state->sam_ldb)));
532 return NT_STATUS_INTERNAL_DB_CORRUPTION;
538 static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
539 struct samsync_ldb_state *state,
540 struct creds_CredentialState *creds,
541 enum netr_SamDatabaseID database,
542 struct netr_DELTA_ENUM *delta)
544 uint32_t rid = delta->delta_id_union.rid;
545 struct netr_DELTA_GROUP_MEMBER *group_member = delta->delta_union.group_member;
546 struct ldb_message *msg;
547 struct ldb_message **msgs;
549 const char *attrs[] = { NULL };
552 msg = ldb_msg_new(mem_ctx);
554 return NT_STATUS_NO_MEMORY;
557 /* search for the group, by rid */
558 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
559 "(&(objectClass=group)(objectSid=%s))",
560 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
563 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
564 return NT_STATUS_INTERNAL_DB_CORRUPTION;
565 } else if (ret == 0) {
566 return NT_STATUS_NO_SUCH_GROUP;
567 } else if (ret > 1) {
568 DEBUG(0, ("More than one group/alias with SID: %s\n",
569 dom_sid_string(mem_ctx,
570 dom_sid_add_rid(mem_ctx,
571 state->dom_sid[database],
573 return NT_STATUS_INTERNAL_DB_CORRUPTION;
575 msg->dn = talloc_steal(msg, msgs[0]->dn);
580 for (i=0; i<group_member->num_rids; i++) {
581 /* search for the group, by rid */
582 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
583 "(&(objectClass=user)(objectSid=%s))",
584 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], group_member->rids[i])));
587 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
588 return NT_STATUS_INTERNAL_DB_CORRUPTION;
589 } else if (ret == 0) {
590 return NT_STATUS_NO_SUCH_USER;
591 } else if (ret > 1) {
592 return NT_STATUS_INTERNAL_DB_CORRUPTION;
594 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, msgs[0]->dn));
600 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
602 DEBUG(0,("Failed to modify group record %s: %s\n",
603 ldb_dn_linearize(mem_ctx, msg->dn),
604 ldb_errstring(state->sam_ldb)));
605 return NT_STATUS_INTERNAL_DB_CORRUPTION;
611 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
612 struct samsync_ldb_state *state,
613 struct creds_CredentialState *creds,
614 enum netr_SamDatabaseID database,
615 struct netr_DELTA_ENUM *delta)
617 uint32_t rid = delta->delta_id_union.rid;
618 struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
619 const char *container, *obj_class;
622 struct ldb_message *msg;
623 struct ldb_message **msgs;
626 const char *attrs[] = { NULL };
628 msg = ldb_msg_new(mem_ctx);
630 return NT_STATUS_NO_MEMORY;
633 /* search for the alias, by rid */
634 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
635 "(&(objectClass=group)(objectSid=%s))",
636 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
639 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
640 return NT_STATUS_INTERNAL_DB_CORRUPTION;
641 } else if (ret == 0) {
643 } else if (ret > 1) {
644 DEBUG(0, ("More than one group/alias with SID: %s\n",
645 dom_sid_string(mem_ctx,
646 dom_sid_add_rid(mem_ctx,
647 state->dom_sid[database],
649 return NT_STATUS_INTERNAL_DB_CORRUPTION;
651 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
654 cn_name = alias->alias_name.string;
656 #define ADD_OR_DEL(type, attrib, field) do {\
657 if (alias->field) { \
658 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
659 attrib, alias->field); \
661 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
666 ADD_OR_DEL(string, "samAccountName", alias_name.string);
668 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
669 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
670 return NT_STATUS_NO_MEMORY;
673 ADD_OR_DEL(string, "description", description.string);
677 samdb_msg_add_uint(state->sam_ldb, mem_ctx, msg, "groupType", 0x80000004);
683 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
684 "objectClass", obj_class);
685 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
686 "CN=%s, CN=%s", cn_name, container);
688 return NT_STATUS_NO_MEMORY;
691 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
693 DEBUG(0,("Failed to create alias record %s: %s\n",
694 ldb_dn_linearize(mem_ctx, msg->dn),
695 ldb_errstring(state->sam_ldb)));
696 return NT_STATUS_INTERNAL_DB_CORRUPTION;
699 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
701 DEBUG(0,("Failed to modify alias record %s: %s\n",
702 ldb_dn_linearize(mem_ctx, msg->dn),
703 ldb_errstring(state->sam_ldb)));
704 return NT_STATUS_INTERNAL_DB_CORRUPTION;
711 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
712 struct samsync_ldb_state *state,
713 struct creds_CredentialState *creds,
714 enum netr_SamDatabaseID database,
715 struct netr_DELTA_ENUM *delta)
717 uint32_t rid = delta->delta_id_union.rid;
718 struct ldb_message **msgs;
720 const char *attrs[] = { NULL };
722 /* search for the alias, by rid */
723 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
724 "(&(objectClass=group)(objectSid=%s))",
725 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
728 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
729 return NT_STATUS_INTERNAL_DB_CORRUPTION;
730 } else if (ret == 0) {
731 return NT_STATUS_NO_SUCH_ALIAS;
732 } else if (ret > 1) {
733 return NT_STATUS_INTERNAL_DB_CORRUPTION;
736 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
738 DEBUG(0,("Failed to delete alias record %s: %s\n",
739 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
740 ldb_errstring(state->sam_ldb)));
741 return NT_STATUS_INTERNAL_DB_CORRUPTION;
747 static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
748 struct samsync_ldb_state *state,
749 struct creds_CredentialState *creds,
750 enum netr_SamDatabaseID database,
751 struct netr_DELTA_ENUM *delta)
753 uint32_t rid = delta->delta_id_union.rid;
754 struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
755 struct ldb_message *msg;
756 struct ldb_message **msgs;
758 const char *attrs[] = { NULL };
761 msg = ldb_msg_new(mem_ctx);
763 return NT_STATUS_NO_MEMORY;
766 /* search for the alias, by rid */
767 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
768 "(&(objectClass=group)(objectSid=%s))",
769 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
772 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
773 return NT_STATUS_INTERNAL_DB_CORRUPTION;
774 } else if (ret == 0) {
775 return NT_STATUS_NO_SUCH_GROUP;
776 } else if (ret > 1) {
777 DEBUG(0, ("More than one group/alias with SID: %s\n",
778 dom_sid_string(mem_ctx,
779 dom_sid_add_rid(mem_ctx,
780 state->dom_sid[database],
782 return NT_STATUS_INTERNAL_DB_CORRUPTION;
784 msg->dn = talloc_steal(msg, msgs[0]->dn);
789 for (i=0; i<alias_member->sids.num_sids; i++) {
790 struct ldb_dn *alias_member_dn;
791 /* search for members, in the top basedn (normal users are builtin aliases) */
792 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
794 ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid));
797 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
798 return NT_STATUS_INTERNAL_DB_CORRUPTION;
799 } else if (ret == 0) {
801 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
802 alias_member->sids.sids[i].sid,
804 if (!NT_STATUS_IS_OK(nt_status)) {
807 } else if (ret > 1) {
808 return NT_STATUS_INTERNAL_DB_CORRUPTION;
810 alias_member_dn = msgs[0]->dn;
812 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, alias_member_dn));
817 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
819 DEBUG(0,("Failed to modify group record %s: %s\n",
820 ldb_dn_linearize(mem_ctx, msg->dn),
821 ldb_errstring(state->sam_ldb)));
822 return NT_STATUS_INTERNAL_DB_CORRUPTION;
828 static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
829 struct samsync_ldb_state *state,
830 struct creds_CredentialState *creds,
831 enum netr_SamDatabaseID database,
832 struct netr_DELTA_ENUM *delta)
834 struct dom_sid *sid = delta->delta_id_union.sid;
835 struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
837 struct ldb_message *msg;
838 struct ldb_message **msgs;
839 struct ldb_dn *privilege_dn;
841 const char *attrs[] = { NULL };
844 msg = ldb_msg_new(mem_ctx);
846 return NT_STATUS_NO_MEMORY;
849 /* search for the account, by sid, in the top basedn */
850 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
851 "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, sid));
854 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
855 return NT_STATUS_INTERNAL_DB_CORRUPTION;
856 } else if (ret == 0) {
858 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
861 privilege_dn = talloc_steal(msg, privilege_dn);
862 if (!NT_STATUS_IS_OK(nt_status)) {
865 } else if (ret > 1) {
866 DEBUG(0, ("More than one account with SID: %s\n",
867 dom_sid_string(mem_ctx, sid)));
868 return NT_STATUS_INTERNAL_DB_CORRUPTION;
870 privilege_dn = talloc_steal(msg, msgs[0]->dn);
873 msg->dn = privilege_dn;
875 for (i=0; i< account->privilege_entries; i++) {
876 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "privilege",
877 account->privilege_name[i].string);
880 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
882 DEBUG(0,("Failed to modify privilege record %s\n",
883 ldb_dn_linearize(mem_ctx, msg->dn)));
884 return NT_STATUS_INTERNAL_DB_CORRUPTION;
890 static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
891 struct samsync_ldb_state *state,
892 struct creds_CredentialState *creds,
893 enum netr_SamDatabaseID database,
894 struct netr_DELTA_ENUM *delta)
896 struct dom_sid *sid = delta->delta_id_union.sid;
898 struct ldb_message *msg;
899 struct ldb_message **msgs;
901 const char *attrs[] = { NULL };
903 msg = ldb_msg_new(mem_ctx);
905 return NT_STATUS_NO_MEMORY;
908 /* search for the account, by sid, in the top basedn */
909 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
911 ldap_encode_ndr_dom_sid(mem_ctx, sid));
914 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
915 return NT_STATUS_INTERNAL_DB_CORRUPTION;
916 } else if (ret == 0) {
917 return NT_STATUS_NO_SUCH_USER;
918 } else if (ret > 1) {
919 DEBUG(0, ("More than one account with SID: %s\n",
920 dom_sid_string(mem_ctx, sid)));
921 return NT_STATUS_INTERNAL_DB_CORRUPTION;
923 msg->dn = talloc_steal(msg, msgs[0]->dn);
926 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
929 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
931 DEBUG(0,("Failed to modify privilege record %s\n",
932 ldb_dn_linearize(mem_ctx, msg->dn)));
933 return NT_STATUS_INTERNAL_DB_CORRUPTION;
939 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,
941 struct creds_CredentialState *creds,
942 enum netr_SamDatabaseID database,
943 struct netr_DELTA_ENUM *delta,
946 NTSTATUS nt_status = NT_STATUS_OK;
947 struct samsync_ldb_state *state = private;
949 *error_string = NULL;
950 switch (delta->delta_type) {
951 case NETR_DELTA_DOMAIN:
953 nt_status = samsync_ldb_handle_domain(mem_ctx,
960 case NETR_DELTA_USER:
962 nt_status = samsync_ldb_handle_user(mem_ctx,
969 case NETR_DELTA_DELETE_USER:
971 nt_status = samsync_ldb_delete_user(mem_ctx,
978 case NETR_DELTA_GROUP:
980 nt_status = samsync_ldb_handle_group(mem_ctx,
987 case NETR_DELTA_DELETE_GROUP:
989 nt_status = samsync_ldb_delete_group(mem_ctx,
996 case NETR_DELTA_GROUP_MEMBER:
998 nt_status = samsync_ldb_handle_group_member(mem_ctx,
1005 case NETR_DELTA_ALIAS:
1007 nt_status = samsync_ldb_handle_alias(mem_ctx,
1014 case NETR_DELTA_DELETE_ALIAS:
1016 nt_status = samsync_ldb_delete_alias(mem_ctx,
1023 case NETR_DELTA_ALIAS_MEMBER:
1025 nt_status = samsync_ldb_handle_alias_member(mem_ctx,
1032 case NETR_DELTA_ACCOUNT:
1034 nt_status = samsync_ldb_handle_account(mem_ctx,
1041 case NETR_DELTA_DELETE_ACCOUNT:
1043 nt_status = samsync_ldb_delete_account(mem_ctx,
1051 /* Can't dump them all right now */
1057 static NTSTATUS libnet_samsync_ldb_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1060 struct libnet_SamSync r2;
1061 struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
1064 return NT_STATUS_NO_MEMORY;
1067 state->secrets = NULL;
1068 state->trusted_domains = NULL;
1070 state->sam_ldb = samdb_connect(state, system_session(state));
1072 r2.error_string = NULL;
1073 r2.delta_fn = libnet_samsync_ldb_fn;
1075 r2.machine_account = NULL; /* TODO: Create a machine account, fill this in, and the delete it */
1076 nt_status = libnet_SamSync_netlogon(ctx, state, &r2);
1077 r->error_string = r2.error_string;
1079 if (!NT_STATUS_IS_OK(nt_status)) {
1089 static NTSTATUS libnet_samsync_ldb_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1092 struct libnet_samsync_ldb r2;
1093 r2.level = LIBNET_SAMSYNC_LDB_NETLOGON;
1094 r2.error_string = NULL;
1095 nt_status = libnet_samsync_ldb(ctx, mem_ctx, &r2);
1096 r->error_string = r2.error_string;
1101 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1104 case LIBNET_SAMSYNC_LDB_GENERIC:
1105 return libnet_samsync_ldb_generic(ctx, mem_ctx, r);
1106 case LIBNET_SAMSYNC_LDB_NETLOGON:
1107 return libnet_samsync_ldb_netlogon(ctx, mem_ctx, r);
1110 return NT_STATUS_INVALID_LEVEL;