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 "libcli/ldap/ldap.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "auth/auth.h"
32 struct samsync_ldb_secret {
33 struct samsync_ldb_secret *prev, *next;
39 struct samsync_ldb_trusted_domain {
40 struct samsync_ldb_trusted_domain *prev, *next;
45 struct samsync_ldb_state {
46 struct dom_sid *dom_sid[3];
47 struct ldb_context *sam_ldb;
48 struct ldb_dn *base_dn[3];
49 struct samsync_ldb_secret *secrets;
50 struct samsync_ldb_trusted_domain *trusted_domains;
53 static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,
54 struct samsync_ldb_state *state,
56 struct ldb_dn **fsp_dn)
58 const char *sidstr = dom_sid_string(mem_ctx, sid);
59 /* We assume that ForeignSecurityPrincipals are under the BASEDN of the main domain */
60 struct ldb_dn *basedn = samdb_search_dn(state->sam_ldb, mem_ctx,
61 state->base_dn[SAM_DATABASE_DOMAIN],
62 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
63 struct ldb_message *msg;
67 return NT_STATUS_NO_MEMORY;
71 DEBUG(0, ("Failed to find DN for "
72 "ForeignSecurityPrincipal container\n"));
73 return NT_STATUS_INTERNAL_DB_CORRUPTION;
76 msg = ldb_msg_new(mem_ctx);
78 return NT_STATUS_NO_MEMORY;
81 /* add core elements to the ldb_message for the alias */
82 msg->dn = ldb_dn_build_child(mem_ctx, "CN", sidstr, basedn);
84 return NT_STATUS_NO_MEMORY;
86 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
88 "foreignSecurityPrincipal");
92 /* create the alias */
93 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
95 DEBUG(0,("Failed to create foreignSecurityPrincipal "
97 ldb_dn_linearize(mem_ctx, msg->dn),
98 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;
120 ret_domain = gendb_search(state->sam_ldb, mem_ctx, NULL, &msgs_domain, domain_attrs,
121 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
123 if (ret_domain == -1) {
124 return NT_STATUS_INTERNAL_DB_CORRUPTION;
127 if (ret_domain != 1) {
128 return NT_STATUS_NO_SUCH_DOMAIN;
131 state->base_dn[database] = samdb_result_dn(state, msgs_domain[0], "nCName", NULL);
133 state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state,
134 state->base_dn[database],
136 } else if (database == SAM_DATABASE_BUILTIN) {
137 /* work out the builtin_dn - useful for so many calls its worth
139 const char *dnstring = samdb_search_string(state->sam_ldb, mem_ctx, NULL,
140 "distinguishedName", "objectClass=builtinDomain");
141 state->base_dn[database] = ldb_dn_explode(state, dnstring);
142 state->dom_sid[database] = dom_sid_parse_talloc(state, SID_BUILTIN);
145 return NT_STATUS_INVALID_PARAMETER;
148 msg = ldb_msg_new(mem_ctx);
150 return NT_STATUS_NO_MEMORY;
153 msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
155 return NT_STATUS_NO_MEMORY;
158 samdb_msg_add_string(state->sam_ldb, mem_ctx,
159 msg, "oEMInformation", domain->comment.string);
161 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
162 msg, "forceLogoff", domain->force_logoff_time);
164 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
165 msg, "minPwdLen", domain->min_password_length);
167 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
168 msg, "maxPwdAge", domain->max_password_age);
170 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
171 msg, "minPwdAge", domain->min_password_age);
173 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
174 msg, "pwdHistoryLength", domain->password_history_length);
176 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
177 msg, "modifiedCount",
178 domain->sequence_num);
180 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
181 msg, "creationTime", domain->domain_create_time);
183 /* TODO: Account lockout, password properties */
185 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
188 return NT_STATUS_INTERNAL_ERROR;
193 static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
194 struct samsync_ldb_state *state,
195 struct creds_CredentialState *creds,
196 enum netr_SamDatabaseID database,
197 struct netr_DELTA_ENUM *delta)
199 uint32_t rid = delta->delta_id_union.rid;
200 struct netr_DELTA_USER *user = delta->delta_union.user;
201 const char *container, *obj_class;
205 struct ldb_message *msg;
206 struct ldb_message **msgs;
210 const char *attrs[] = { NULL };
212 msg = ldb_msg_new(mem_ctx);
214 return NT_STATUS_NO_MEMORY;
217 /* search for the user, by rid */
218 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
219 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
220 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
223 return NT_STATUS_INTERNAL_DB_CORRUPTION;
224 } else if (ret == 0) {
226 } else if (ret > 1) {
227 DEBUG(0, ("More than one user with SID: %s\n",
228 dom_sid_string(mem_ctx,
229 dom_sid_add_rid(mem_ctx,
230 state->dom_sid[database],
232 return NT_STATUS_INTERNAL_DB_CORRUPTION;
234 msg->dn = talloc_steal(msg, msgs[0]->dn);
238 cn_name = talloc_strdup(mem_ctx, user->account_name.string);
239 NT_STATUS_HAVE_NO_MEMORY(cn_name);
240 cn_name_len = strlen(cn_name);
242 #define ADD_OR_DEL(type, attrib, field) do {\
244 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
245 attrib, user->field); \
247 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
252 ADD_OR_DEL(string, "samAccountName", account_name.string);
253 ADD_OR_DEL(string, "displayName", full_name.string);
255 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
256 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
257 return NT_STATUS_NO_MEMORY;
260 ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
261 ADD_OR_DEL(string, "homeDirectory", home_directory.string);
262 ADD_OR_DEL(string, "homeDrive", home_drive.string);
263 ADD_OR_DEL(string, "scriptPath", logon_script.string);
264 ADD_OR_DEL(string, "description", description.string);
265 ADD_OR_DEL(string, "userWorkstations", workstations.string);
267 ADD_OR_DEL(uint64, "lastLogon", last_logon);
268 ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
270 if (samdb_msg_add_logon_hours(state->sam_ldb, mem_ctx, msg, "logonHours", &user->logon_hours) != 0) {
271 return NT_STATUS_NO_MEMORY;
274 ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
275 ADD_OR_DEL(uint, "logonCount", logon_count);
277 ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
278 ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
280 if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg,
281 "userAccountControl", user->acct_flags) != 0) {
282 return NT_STATUS_NO_MEMORY;
285 /* Passwords. Ensure there is no plaintext stored against
286 * this entry, as we only have hashes */
287 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
289 if (user->lm_password_present) {
290 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
291 "lmPwdHash", &user->lmpassword);
293 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
296 if (user->nt_password_present) {
297 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
298 "ntPwdHash", &user->ntpassword);
300 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
304 ADD_OR_DEL(string, "comment", comment.string);
305 ADD_OR_DEL(string, "userParameters", parameters.string);
306 ADD_OR_DEL(uint, "countryCode", country_code);
307 ADD_OR_DEL(uint, "codePage", code_page);
309 ADD_OR_DEL(string, "profilePath", profile_path.string);
313 acb = user->acct_flags;
314 if (acb & (ACB_WSTRUST)) {
315 cn_name[cn_name_len - 1] = '\0';
316 container = "Computers";
317 obj_class = "computer";
319 } else if (acb & ACB_SVRTRUST) {
320 if (cn_name[cn_name_len - 1] != '$') {
321 return NT_STATUS_FOOBAR;
323 cn_name[cn_name_len - 1] = '\0';
324 container = "Domain Controllers";
325 obj_class = "computer";
331 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
332 "objectClass", obj_class);
333 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
334 "CN=%s, CN=%s", cn_name, container);
336 return NT_STATUS_NO_MEMORY;
339 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
341 DEBUG(0,("Failed to create user record %s\n",
342 ldb_dn_linearize(mem_ctx, msg->dn)));
343 return NT_STATUS_INTERNAL_DB_CORRUPTION;
346 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
348 DEBUG(0,("Failed to modify user record %s\n",
349 ldb_dn_linearize(mem_ctx, msg->dn)));
350 return NT_STATUS_INTERNAL_DB_CORRUPTION;
357 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
358 struct samsync_ldb_state *state,
359 struct creds_CredentialState *creds,
360 enum netr_SamDatabaseID database,
361 struct netr_DELTA_ENUM *delta)
363 uint32_t rid = delta->delta_id_union.rid;
364 struct ldb_message **msgs;
366 const char *attrs[] = { NULL };
368 /* search for the user, by rid */
369 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
370 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
371 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
374 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
375 return NT_STATUS_INTERNAL_DB_CORRUPTION;
376 } else if (ret == 0) {
377 return NT_STATUS_NO_SUCH_USER;
378 } else if (ret > 1) {
379 DEBUG(0, ("More than one user with SID: %s\n",
380 dom_sid_string(mem_ctx,
381 dom_sid_add_rid(mem_ctx,
382 state->dom_sid[database],
384 return NT_STATUS_INTERNAL_DB_CORRUPTION;
387 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
389 DEBUG(0,("Failed to delete user record %s: %s\n",
390 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
391 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 = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
471 "CN=%s, CN=%s", cn_name, container);
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",
479 ldb_dn_linearize(mem_ctx, msg->dn),
480 ldb_errstring(state->sam_ldb)));
481 return NT_STATUS_INTERNAL_DB_CORRUPTION;
484 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
486 DEBUG(0,("Failed to modify group record %s: %s\n",
487 ldb_dn_linearize(mem_ctx, msg->dn),
488 ldb_errstring(state->sam_ldb)));
489 return NT_STATUS_INTERNAL_DB_CORRUPTION;
496 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
497 struct samsync_ldb_state *state,
498 struct creds_CredentialState *creds,
499 enum netr_SamDatabaseID database,
500 struct netr_DELTA_ENUM *delta)
502 uint32_t rid = delta->delta_id_union.rid;
503 struct ldb_message **msgs;
505 const char *attrs[] = { NULL };
507 /* search for the group, by rid */
508 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
509 "(&(objectClass=group)(objectSid=%s))",
510 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
513 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
514 return NT_STATUS_INTERNAL_DB_CORRUPTION;
515 } else if (ret == 0) {
516 return NT_STATUS_NO_SUCH_GROUP;
517 } else if (ret > 1) {
518 DEBUG(0, ("More than one group/alias with SID: %s\n",
519 dom_sid_string(mem_ctx,
520 dom_sid_add_rid(mem_ctx,
521 state->dom_sid[database],
523 return NT_STATUS_INTERNAL_DB_CORRUPTION;
526 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
528 DEBUG(0,("Failed to delete group record %s: %s\n",
529 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
530 ldb_errstring(state->sam_ldb)));
531 return NT_STATUS_INTERNAL_DB_CORRUPTION;
537 static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
538 struct samsync_ldb_state *state,
539 struct creds_CredentialState *creds,
540 enum netr_SamDatabaseID database,
541 struct netr_DELTA_ENUM *delta)
543 uint32_t rid = delta->delta_id_union.rid;
544 struct netr_DELTA_GROUP_MEMBER *group_member = delta->delta_union.group_member;
545 struct ldb_message *msg;
546 struct ldb_message **msgs;
548 const char *attrs[] = { NULL };
551 msg = ldb_msg_new(mem_ctx);
553 return NT_STATUS_NO_MEMORY;
556 /* search for the group, by rid */
557 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
558 "(&(objectClass=group)(objectSid=%s))",
559 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
562 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
563 return NT_STATUS_INTERNAL_DB_CORRUPTION;
564 } else if (ret == 0) {
565 return NT_STATUS_NO_SUCH_GROUP;
566 } else if (ret > 1) {
567 DEBUG(0, ("More than one group/alias with SID: %s\n",
568 dom_sid_string(mem_ctx,
569 dom_sid_add_rid(mem_ctx,
570 state->dom_sid[database],
572 return NT_STATUS_INTERNAL_DB_CORRUPTION;
574 msg->dn = talloc_steal(msg, msgs[0]->dn);
579 for (i=0; i<group_member->num_rids; i++) {
580 /* search for the group, by rid */
581 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
582 "(&(objectClass=user)(objectSid=%s))",
583 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], group_member->rids[i])));
586 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
587 return NT_STATUS_INTERNAL_DB_CORRUPTION;
588 } else if (ret == 0) {
589 return NT_STATUS_NO_SUCH_USER;
590 } else if (ret > 1) {
591 return NT_STATUS_INTERNAL_DB_CORRUPTION;
593 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, msgs[0]->dn));
599 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
601 DEBUG(0,("Failed to modify group record %s: %s\n",
602 ldb_dn_linearize(mem_ctx, msg->dn),
603 ldb_errstring(state->sam_ldb)));
604 return NT_STATUS_INTERNAL_DB_CORRUPTION;
610 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
611 struct samsync_ldb_state *state,
612 struct creds_CredentialState *creds,
613 enum netr_SamDatabaseID database,
614 struct netr_DELTA_ENUM *delta)
616 uint32_t rid = delta->delta_id_union.rid;
617 struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
618 const char *container, *obj_class;
621 struct ldb_message *msg;
622 struct ldb_message **msgs;
625 const char *attrs[] = { NULL };
627 msg = ldb_msg_new(mem_ctx);
629 return NT_STATUS_NO_MEMORY;
632 /* search for the alias, by rid */
633 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
634 "(&(objectClass=group)(objectSid=%s))",
635 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
638 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
639 return NT_STATUS_INTERNAL_DB_CORRUPTION;
640 } else if (ret == 0) {
642 } else if (ret > 1) {
643 DEBUG(0, ("More than one group/alias with SID: %s\n",
644 dom_sid_string(mem_ctx,
645 dom_sid_add_rid(mem_ctx,
646 state->dom_sid[database],
648 return NT_STATUS_INTERNAL_DB_CORRUPTION;
650 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
653 cn_name = alias->alias_name.string;
655 #define ADD_OR_DEL(type, attrib, field) do {\
656 if (alias->field) { \
657 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
658 attrib, alias->field); \
660 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
665 ADD_OR_DEL(string, "samAccountName", alias_name.string);
667 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
668 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
669 return NT_STATUS_NO_MEMORY;
672 ADD_OR_DEL(string, "description", description.string);
676 samdb_msg_add_uint(state->sam_ldb, mem_ctx, msg, "groupType", 0x80000004);
682 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
683 "objectClass", obj_class);
684 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
685 "CN=%s, CN=%s", cn_name, container);
687 return NT_STATUS_NO_MEMORY;
690 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
692 DEBUG(0,("Failed to create alias record %s: %s\n",
693 ldb_dn_linearize(mem_ctx, msg->dn),
694 ldb_errstring(state->sam_ldb)));
695 return NT_STATUS_INTERNAL_DB_CORRUPTION;
698 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
700 DEBUG(0,("Failed to modify alias record %s: %s\n",
701 ldb_dn_linearize(mem_ctx, msg->dn),
702 ldb_errstring(state->sam_ldb)));
703 return NT_STATUS_INTERNAL_DB_CORRUPTION;
710 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
711 struct samsync_ldb_state *state,
712 struct creds_CredentialState *creds,
713 enum netr_SamDatabaseID database,
714 struct netr_DELTA_ENUM *delta)
716 uint32_t rid = delta->delta_id_union.rid;
717 struct ldb_message **msgs;
719 const char *attrs[] = { NULL };
721 /* search for the alias, by rid */
722 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
723 "(&(objectClass=group)(objectSid=%s))",
724 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
727 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
728 return NT_STATUS_INTERNAL_DB_CORRUPTION;
729 } else if (ret == 0) {
730 return NT_STATUS_NO_SUCH_ALIAS;
731 } else if (ret > 1) {
732 return NT_STATUS_INTERNAL_DB_CORRUPTION;
735 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
737 DEBUG(0,("Failed to delete alias record %s: %s\n",
738 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
739 ldb_errstring(state->sam_ldb)));
740 return NT_STATUS_INTERNAL_DB_CORRUPTION;
746 static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
747 struct samsync_ldb_state *state,
748 struct creds_CredentialState *creds,
749 enum netr_SamDatabaseID database,
750 struct netr_DELTA_ENUM *delta)
752 uint32_t rid = delta->delta_id_union.rid;
753 struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
754 struct ldb_message *msg;
755 struct ldb_message **msgs;
757 const char *attrs[] = { NULL };
760 msg = ldb_msg_new(mem_ctx);
762 return NT_STATUS_NO_MEMORY;
765 /* search for the alias, by rid */
766 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
767 "(&(objectClass=group)(objectSid=%s))",
768 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
771 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
772 return NT_STATUS_INTERNAL_DB_CORRUPTION;
773 } else if (ret == 0) {
774 return NT_STATUS_NO_SUCH_GROUP;
775 } else if (ret > 1) {
776 DEBUG(0, ("More than one group/alias with SID: %s\n",
777 dom_sid_string(mem_ctx,
778 dom_sid_add_rid(mem_ctx,
779 state->dom_sid[database],
781 return NT_STATUS_INTERNAL_DB_CORRUPTION;
783 msg->dn = talloc_steal(msg, msgs[0]->dn);
788 for (i=0; i<alias_member->sids.num_sids; i++) {
789 struct ldb_dn *alias_member_dn;
790 /* search for members, in the top basedn (normal users are builtin aliases) */
791 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
793 ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid));
796 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
797 return NT_STATUS_INTERNAL_DB_CORRUPTION;
798 } else if (ret == 0) {
800 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
801 alias_member->sids.sids[i].sid,
803 if (!NT_STATUS_IS_OK(nt_status)) {
806 } else if (ret > 1) {
807 return NT_STATUS_INTERNAL_DB_CORRUPTION;
809 alias_member_dn = msgs[0]->dn;
811 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, alias_member_dn));
816 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
818 DEBUG(0,("Failed to modify group record %s: %s\n",
819 ldb_dn_linearize(mem_ctx, msg->dn),
820 ldb_errstring(state->sam_ldb)));
821 return NT_STATUS_INTERNAL_DB_CORRUPTION;
827 static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
828 struct samsync_ldb_state *state,
829 struct creds_CredentialState *creds,
830 enum netr_SamDatabaseID database,
831 struct netr_DELTA_ENUM *delta)
833 struct dom_sid *sid = delta->delta_id_union.sid;
834 struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
836 struct ldb_message *msg;
837 struct ldb_message **msgs;
838 struct ldb_dn *privilege_dn;
840 const char *attrs[] = { NULL };
843 msg = ldb_msg_new(mem_ctx);
845 return NT_STATUS_NO_MEMORY;
848 /* search for the account, by sid, in the top basedn */
849 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
850 "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, sid));
853 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
854 return NT_STATUS_INTERNAL_DB_CORRUPTION;
855 } else if (ret == 0) {
857 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
860 privilege_dn = talloc_steal(msg, privilege_dn);
861 if (!NT_STATUS_IS_OK(nt_status)) {
864 } else if (ret > 1) {
865 DEBUG(0, ("More than one account with SID: %s\n",
866 dom_sid_string(mem_ctx, sid)));
867 return NT_STATUS_INTERNAL_DB_CORRUPTION;
869 privilege_dn = talloc_steal(msg, msgs[0]->dn);
872 msg->dn = privilege_dn;
874 for (i=0; i< account->privilege_entries; i++) {
875 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "privilege",
876 account->privilege_name[i].string);
879 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
881 DEBUG(0,("Failed to modify privilege record %s\n",
882 ldb_dn_linearize(mem_ctx, msg->dn)));
883 return NT_STATUS_INTERNAL_DB_CORRUPTION;
889 static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
890 struct samsync_ldb_state *state,
891 struct creds_CredentialState *creds,
892 enum netr_SamDatabaseID database,
893 struct netr_DELTA_ENUM *delta)
895 struct dom_sid *sid = delta->delta_id_union.sid;
897 struct ldb_message *msg;
898 struct ldb_message **msgs;
900 const char *attrs[] = { NULL };
902 msg = ldb_msg_new(mem_ctx);
904 return NT_STATUS_NO_MEMORY;
907 /* search for the account, by sid, in the top basedn */
908 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
910 ldap_encode_ndr_dom_sid(mem_ctx, sid));
913 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
914 return NT_STATUS_INTERNAL_DB_CORRUPTION;
915 } else if (ret == 0) {
916 return NT_STATUS_NO_SUCH_USER;
917 } else if (ret > 1) {
918 DEBUG(0, ("More than one account with SID: %s\n",
919 dom_sid_string(mem_ctx, sid)));
920 return NT_STATUS_INTERNAL_DB_CORRUPTION;
922 msg->dn = talloc_steal(msg, msgs[0]->dn);
925 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
928 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
930 DEBUG(0,("Failed to modify privilege record %s\n",
931 ldb_dn_linearize(mem_ctx, msg->dn)));
932 return NT_STATUS_INTERNAL_DB_CORRUPTION;
938 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,
940 struct creds_CredentialState *creds,
941 enum netr_SamDatabaseID database,
942 struct netr_DELTA_ENUM *delta,
945 NTSTATUS nt_status = NT_STATUS_OK;
946 struct samsync_ldb_state *state = private;
948 *error_string = NULL;
949 switch (delta->delta_type) {
950 case NETR_DELTA_DOMAIN:
952 nt_status = samsync_ldb_handle_domain(mem_ctx,
959 case NETR_DELTA_USER:
961 nt_status = samsync_ldb_handle_user(mem_ctx,
968 case NETR_DELTA_DELETE_USER:
970 nt_status = samsync_ldb_delete_user(mem_ctx,
977 case NETR_DELTA_GROUP:
979 nt_status = samsync_ldb_handle_group(mem_ctx,
986 case NETR_DELTA_DELETE_GROUP:
988 nt_status = samsync_ldb_delete_group(mem_ctx,
995 case NETR_DELTA_GROUP_MEMBER:
997 nt_status = samsync_ldb_handle_group_member(mem_ctx,
1004 case NETR_DELTA_ALIAS:
1006 nt_status = samsync_ldb_handle_alias(mem_ctx,
1013 case NETR_DELTA_DELETE_ALIAS:
1015 nt_status = samsync_ldb_delete_alias(mem_ctx,
1022 case NETR_DELTA_ALIAS_MEMBER:
1024 nt_status = samsync_ldb_handle_alias_member(mem_ctx,
1031 case NETR_DELTA_ACCOUNT:
1033 nt_status = samsync_ldb_handle_account(mem_ctx,
1040 case NETR_DELTA_DELETE_ACCOUNT:
1042 nt_status = samsync_ldb_delete_account(mem_ctx,
1050 /* Can't dump them all right now */
1056 static NTSTATUS libnet_samsync_ldb_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1059 struct libnet_SamSync r2;
1060 struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
1063 return NT_STATUS_NO_MEMORY;
1066 state->secrets = NULL;
1067 state->trusted_domains = NULL;
1069 state->sam_ldb = samdb_connect(state, system_session(state));
1071 r2.error_string = NULL;
1072 r2.delta_fn = libnet_samsync_ldb_fn;
1074 r2.machine_account = NULL; /* TODO: Create a machine account, fill this in, and the delete it */
1075 nt_status = libnet_SamSync_netlogon(ctx, state, &r2);
1076 r->error_string = r2.error_string;
1078 if (!NT_STATUS_IS_OK(nt_status)) {
1088 static NTSTATUS libnet_samsync_ldb_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1091 struct libnet_samsync_ldb r2;
1092 r2.level = LIBNET_SAMSYNC_LDB_NETLOGON;
1093 r2.error_string = NULL;
1094 nt_status = libnet_samsync_ldb(ctx, mem_ctx, &r2);
1095 r->error_string = r2.error_string;
1100 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1103 case LIBNET_SAMSYNC_LDB_GENERIC:
1104 return libnet_samsync_ldb_generic(ctx, mem_ctx, r);
1105 case LIBNET_SAMSYNC_LDB_NETLOGON:
1106 return libnet_samsync_ldb_netlogon(ctx, mem_ctx, r);
1109 return NT_STATUS_INVALID_LEVEL;