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 = ldb_dn_explode(mem_ctx,
62 samdb_search_string(state->sam_ldb, mem_ctx,
63 state->base_dn[SAM_DATABASE_DOMAIN],
64 "dn", "(&(objectClass=container)"
65 "(cn=ForeignSecurityPrincipals))"));
66 struct ldb_message *msg;
70 return NT_STATUS_NO_MEMORY;
74 DEBUG(0, ("Failed to find DN for "
75 "ForeignSecurityPrincipal container\n"));
76 return NT_STATUS_INTERNAL_DB_CORRUPTION;
79 msg = ldb_msg_new(mem_ctx);
81 return NT_STATUS_NO_MEMORY;
84 /* add core elements to the ldb_message for the alias */
85 msg->dn = ldb_dn_build_child(mem_ctx, "CN", sidstr, basedn);
87 return NT_STATUS_NO_MEMORY;
89 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
91 "foreignSecurityPrincipal");
95 /* create the alias */
96 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
98 DEBUG(0,("Failed to create foreignSecurityPrincipal "
100 ldb_dn_linearize(mem_ctx, msg->dn),
101 ldb_errstring(state->sam_ldb)));
102 return NT_STATUS_INTERNAL_DB_CORRUPTION;
107 static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
108 struct samsync_ldb_state *state,
109 struct creds_CredentialState *creds,
110 enum netr_SamDatabaseID database,
111 struct netr_DELTA_ENUM *delta)
113 struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;
114 const char *domain_name = domain->domain_name.string;
115 struct ldb_message *msg;
118 if (database == SAM_DATABASE_DOMAIN) {
119 const char *domain_attrs[] = {"nETBIOSName", "nCName", NULL};
120 struct ldb_message **msgs_domain;
122 ret_domain = gendb_search(state->sam_ldb, mem_ctx, NULL, &msgs_domain, domain_attrs,
123 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
125 if (ret_domain == -1) {
126 return NT_STATUS_INTERNAL_DB_CORRUPTION;
129 if (ret_domain != 1) {
130 return NT_STATUS_NO_SUCH_DOMAIN;
133 state->base_dn[database]
134 = talloc_steal(state, samdb_result_string(msgs_domain[0],
137 state->dom_sid[database]
138 = talloc_steal(state,
139 samdb_search_dom_sid(state->sam_ldb, state,
140 state->base_dn[database], "objectSid", "dn=%s",
141 ldb_dn_linearize(mem_ctx, state->base_dn[database])));
142 } else if (database == SAM_DATABASE_BUILTIN) {
143 /* work out the builtin_dn - useful for so many calls its worth
145 state->base_dn[database]
146 = talloc_steal(state,
147 samdb_search_string(state->sam_ldb, mem_ctx, NULL,
148 "dn", "objectClass=builtinDomain"));
149 state->dom_sid[database]
150 = dom_sid_parse_talloc(state, SID_BUILTIN);
153 return NT_STATUS_INVALID_PARAMETER;
156 msg = ldb_msg_new(mem_ctx);
158 return NT_STATUS_NO_MEMORY;
161 msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
163 return NT_STATUS_NO_MEMORY;
166 samdb_msg_add_string(state->sam_ldb, mem_ctx,
167 msg, "oEMInformation", domain->comment.string);
169 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
170 msg, "forceLogoff", domain->force_logoff_time);
172 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
173 msg, "minPwdLen", domain->min_password_length);
175 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
176 msg, "maxPwdAge", domain->max_password_age);
178 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
179 msg, "minPwdAge", domain->min_password_age);
181 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
182 msg, "pwdHistoryLength", domain->password_history_length);
184 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
185 msg, "modifiedCount",
186 domain->sequence_num);
188 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
189 msg, "creationTime", domain->domain_create_time);
191 /* TODO: Account lockout, password properties */
193 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
196 return NT_STATUS_INTERNAL_ERROR;
201 static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
202 struct samsync_ldb_state *state,
203 struct creds_CredentialState *creds,
204 enum netr_SamDatabaseID database,
205 struct netr_DELTA_ENUM *delta)
207 uint32_t rid = delta->delta_id_union.rid;
208 struct netr_DELTA_USER *user = delta->delta_union.user;
209 const char *container, *obj_class;
213 struct ldb_message *msg;
214 struct ldb_message **msgs;
218 const char *attrs[] = { NULL };
220 msg = ldb_msg_new(mem_ctx);
222 return NT_STATUS_NO_MEMORY;
225 /* search for the user, by rid */
226 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
227 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
228 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
231 return NT_STATUS_INTERNAL_DB_CORRUPTION;
232 } else if (ret == 0) {
234 } else if (ret > 1) {
235 DEBUG(0, ("More than one user with SID: %s\n",
236 dom_sid_string(mem_ctx,
237 dom_sid_add_rid(mem_ctx,
238 state->dom_sid[database],
240 return NT_STATUS_INTERNAL_DB_CORRUPTION;
242 msg->dn = talloc_steal(msg, msgs[0]->dn);
246 cn_name = talloc_strdup(mem_ctx, user->account_name.string);
247 NT_STATUS_HAVE_NO_MEMORY(cn_name);
248 cn_name_len = strlen(cn_name);
250 #define ADD_OR_DEL(type, attrib, field) do {\
252 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
253 attrib, user->field); \
255 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
260 ADD_OR_DEL(string, "samAccountName", account_name.string);
261 ADD_OR_DEL(string, "displayName", full_name.string);
263 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
264 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
265 return NT_STATUS_NO_MEMORY;
268 ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
269 ADD_OR_DEL(string, "homeDirectory", home_directory.string);
270 ADD_OR_DEL(string, "homeDrive", home_drive.string);
271 ADD_OR_DEL(string, "scriptPath", logon_script.string);
272 ADD_OR_DEL(string, "description", description.string);
273 ADD_OR_DEL(string, "userWorkstations", workstations.string);
275 ADD_OR_DEL(uint64, "lastLogon", last_logon);
276 ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
278 if (samdb_msg_add_logon_hours(state->sam_ldb, mem_ctx, msg, "logonHours", &user->logon_hours) != 0) {
279 return NT_STATUS_NO_MEMORY;
282 ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
283 ADD_OR_DEL(uint, "logonCount", logon_count);
285 ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
286 ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
288 if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg,
289 "userAccountControl", user->acct_flags) != 0) {
290 return NT_STATUS_NO_MEMORY;
294 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
296 if (user->lm_password_present) {
297 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
298 "lmPwdHash", &user->lmpassword);
300 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
303 if (user->nt_password_present) {
304 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
305 "ntPwdHash", &user->ntpassword);
307 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
311 ADD_OR_DEL(string, "comment", comment.string);
312 ADD_OR_DEL(string, "userParameters", parameters.string);
313 ADD_OR_DEL(uint, "countryCode", country_code);
314 ADD_OR_DEL(uint, "codePage", code_page);
316 ADD_OR_DEL(string, "profilePath", profile_path.string);
320 acb = user->acct_flags;
321 if (acb & (ACB_WSTRUST)) {
322 cn_name[cn_name_len - 1] = '\0';
323 container = "Computers";
324 obj_class = "computer";
326 } else if (acb & ACB_SVRTRUST) {
327 if (cn_name[cn_name_len - 1] != '$') {
328 return NT_STATUS_FOOBAR;
330 cn_name[cn_name_len - 1] = '\0';
331 container = "Domain Controllers";
332 obj_class = "computer";
338 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
339 "objectClass", obj_class);
340 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
341 "CN=%s, CN=%s", cn_name, container);
343 return NT_STATUS_NO_MEMORY;
346 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
348 DEBUG(0,("Failed to create user record %s\n",
349 ldb_dn_linearize(mem_ctx, msg->dn)));
350 return NT_STATUS_INTERNAL_DB_CORRUPTION;
353 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
355 DEBUG(0,("Failed to modify user record %s\n",
356 ldb_dn_linearize(mem_ctx, msg->dn)));
357 return NT_STATUS_INTERNAL_DB_CORRUPTION;
364 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
365 struct samsync_ldb_state *state,
366 struct creds_CredentialState *creds,
367 enum netr_SamDatabaseID database,
368 struct netr_DELTA_ENUM *delta)
370 uint32_t rid = delta->delta_id_union.rid;
371 struct ldb_message **msgs;
373 const char *attrs[] = { NULL };
375 /* search for the user, by rid */
376 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
377 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
378 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
381 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
382 return NT_STATUS_INTERNAL_DB_CORRUPTION;
383 } else if (ret == 0) {
384 return NT_STATUS_NO_SUCH_USER;
385 } else if (ret > 1) {
386 DEBUG(0, ("More than one user with SID: %s\n",
387 dom_sid_string(mem_ctx,
388 dom_sid_add_rid(mem_ctx,
389 state->dom_sid[database],
391 return NT_STATUS_INTERNAL_DB_CORRUPTION;
394 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
396 DEBUG(0,("Failed to delete user record %s: %s\n",
397 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
398 ldb_errstring(state->sam_ldb)));
399 return NT_STATUS_INTERNAL_DB_CORRUPTION;
405 static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
406 struct samsync_ldb_state *state,
407 struct creds_CredentialState *creds,
408 enum netr_SamDatabaseID database,
409 struct netr_DELTA_ENUM *delta)
411 uint32_t rid = delta->delta_id_union.rid;
412 struct netr_DELTA_GROUP *group = delta->delta_union.group;
413 const char *container, *obj_class;
416 struct ldb_message *msg;
417 struct ldb_message **msgs;
420 const char *attrs[] = { NULL };
422 msg = ldb_msg_new(mem_ctx);
424 return NT_STATUS_NO_MEMORY;
427 /* search for the group, by rid */
428 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
429 "(&(objectClass=group)(objectSid=%s))",
430 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
433 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
434 return NT_STATUS_INTERNAL_DB_CORRUPTION;
435 } else if (ret == 0) {
437 } else if (ret > 1) {
438 DEBUG(0, ("More than one group/alias with SID: %s\n",
439 dom_sid_string(mem_ctx,
440 dom_sid_add_rid(mem_ctx,
441 state->dom_sid[database],
443 return NT_STATUS_INTERNAL_DB_CORRUPTION;
445 msg->dn = talloc_steal(msg, msgs[0]->dn);
448 cn_name = group->group_name.string;
450 #define ADD_OR_DEL(type, attrib, field) do {\
451 if (group->field) { \
452 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
453 attrib, group->field); \
455 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
460 ADD_OR_DEL(string, "samAccountName", group_name.string);
462 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
463 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
464 return NT_STATUS_NO_MEMORY;
467 ADD_OR_DEL(string, "description", description.string);
475 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
476 "objectClass", obj_class);
477 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
478 "CN=%s, CN=%s", cn_name, container);
480 return NT_STATUS_NO_MEMORY;
483 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
485 DEBUG(0,("Failed to create group record %s: %s\n",
486 ldb_dn_linearize(mem_ctx, msg->dn),
487 ldb_errstring(state->sam_ldb)));
488 return NT_STATUS_INTERNAL_DB_CORRUPTION;
491 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
493 DEBUG(0,("Failed to modify group record %s: %s\n",
494 ldb_dn_linearize(mem_ctx, msg->dn),
495 ldb_errstring(state->sam_ldb)));
496 return NT_STATUS_INTERNAL_DB_CORRUPTION;
503 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
504 struct samsync_ldb_state *state,
505 struct creds_CredentialState *creds,
506 enum netr_SamDatabaseID database,
507 struct netr_DELTA_ENUM *delta)
509 uint32_t rid = delta->delta_id_union.rid;
510 struct ldb_message **msgs;
512 const char *attrs[] = { NULL };
514 /* search for the group, by rid */
515 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
516 "(&(objectClass=group)(objectSid=%s))",
517 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
520 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
521 return NT_STATUS_INTERNAL_DB_CORRUPTION;
522 } else if (ret == 0) {
523 return NT_STATUS_NO_SUCH_GROUP;
524 } else if (ret > 1) {
525 DEBUG(0, ("More than one group/alias with SID: %s\n",
526 dom_sid_string(mem_ctx,
527 dom_sid_add_rid(mem_ctx,
528 state->dom_sid[database],
530 return NT_STATUS_INTERNAL_DB_CORRUPTION;
533 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
535 DEBUG(0,("Failed to delete group record %s: %s\n",
536 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
537 ldb_errstring(state->sam_ldb)));
538 return NT_STATUS_INTERNAL_DB_CORRUPTION;
544 static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
545 struct samsync_ldb_state *state,
546 struct creds_CredentialState *creds,
547 enum netr_SamDatabaseID database,
548 struct netr_DELTA_ENUM *delta)
550 uint32_t rid = delta->delta_id_union.rid;
551 struct netr_DELTA_GROUP_MEMBER *group_member = delta->delta_union.group_member;
552 struct ldb_message *msg;
553 struct ldb_message **msgs;
555 const char *attrs[] = { NULL };
558 msg = ldb_msg_new(mem_ctx);
560 return NT_STATUS_NO_MEMORY;
563 /* search for the group, by rid */
564 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
565 "(&(objectClass=group)(objectSid=%s))",
566 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
569 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
570 return NT_STATUS_INTERNAL_DB_CORRUPTION;
571 } else if (ret == 0) {
572 return NT_STATUS_NO_SUCH_GROUP;
573 } else if (ret > 1) {
574 DEBUG(0, ("More than one group/alias with SID: %s\n",
575 dom_sid_string(mem_ctx,
576 dom_sid_add_rid(mem_ctx,
577 state->dom_sid[database],
579 return NT_STATUS_INTERNAL_DB_CORRUPTION;
581 msg->dn = talloc_steal(msg, msgs[0]->dn);
586 for (i=0; i<group_member->num_rids; i++) {
587 /* search for the group, by rid */
588 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
589 "(&(objectClass=user)(objectSid=%s))",
590 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], group_member->rids[i])));
593 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
594 return NT_STATUS_INTERNAL_DB_CORRUPTION;
595 } else if (ret == 0) {
596 return NT_STATUS_NO_SUCH_USER;
597 } else if (ret > 1) {
598 return NT_STATUS_INTERNAL_DB_CORRUPTION;
600 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, msgs[0]->dn));
606 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
608 DEBUG(0,("Failed to modify group record %s: %s\n",
609 ldb_dn_linearize(mem_ctx, msg->dn),
610 ldb_errstring(state->sam_ldb)));
611 return NT_STATUS_INTERNAL_DB_CORRUPTION;
617 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
618 struct samsync_ldb_state *state,
619 struct creds_CredentialState *creds,
620 enum netr_SamDatabaseID database,
621 struct netr_DELTA_ENUM *delta)
623 uint32_t rid = delta->delta_id_union.rid;
624 struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
625 const char *container, *obj_class;
628 struct ldb_message *msg;
629 struct ldb_message **msgs;
632 const char *attrs[] = { NULL };
634 msg = ldb_msg_new(mem_ctx);
636 return NT_STATUS_NO_MEMORY;
639 /* search for the alias, by rid */
640 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
641 "(&(objectClass=group)(objectSid=%s))",
642 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
645 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
646 return NT_STATUS_INTERNAL_DB_CORRUPTION;
647 } else if (ret == 0) {
649 } else if (ret > 1) {
650 DEBUG(0, ("More than one group/alias with SID: %s\n",
651 dom_sid_string(mem_ctx,
652 dom_sid_add_rid(mem_ctx,
653 state->dom_sid[database],
655 return NT_STATUS_INTERNAL_DB_CORRUPTION;
657 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
660 cn_name = alias->alias_name.string;
662 #define ADD_OR_DEL(type, attrib, field) do {\
663 if (alias->field) { \
664 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
665 attrib, alias->field); \
667 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
672 ADD_OR_DEL(string, "samAccountName", alias_name.string);
674 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
675 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
676 return NT_STATUS_NO_MEMORY;
679 ADD_OR_DEL(string, "description", description.string);
683 samdb_msg_add_uint(state->sam_ldb, mem_ctx, msg, "groupType", 0x80000004);
689 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
690 "objectClass", obj_class);
691 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
692 "CN=%s, CN=%s", cn_name, container);
694 return NT_STATUS_NO_MEMORY;
697 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
699 DEBUG(0,("Failed to create alias record %s: %s\n",
700 ldb_dn_linearize(mem_ctx, msg->dn),
701 ldb_errstring(state->sam_ldb)));
702 return NT_STATUS_INTERNAL_DB_CORRUPTION;
705 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
707 DEBUG(0,("Failed to modify alias record %s: %s\n",
708 ldb_dn_linearize(mem_ctx, msg->dn),
709 ldb_errstring(state->sam_ldb)));
710 return NT_STATUS_INTERNAL_DB_CORRUPTION;
717 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
718 struct samsync_ldb_state *state,
719 struct creds_CredentialState *creds,
720 enum netr_SamDatabaseID database,
721 struct netr_DELTA_ENUM *delta)
723 uint32_t rid = delta->delta_id_union.rid;
724 struct ldb_message **msgs;
726 const char *attrs[] = { NULL };
728 /* search for the alias, by rid */
729 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
730 "(&(objectClass=group)(objectSid=%s))",
731 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
734 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
735 return NT_STATUS_INTERNAL_DB_CORRUPTION;
736 } else if (ret == 0) {
737 return NT_STATUS_NO_SUCH_ALIAS;
738 } else if (ret > 1) {
739 return NT_STATUS_INTERNAL_DB_CORRUPTION;
742 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
744 DEBUG(0,("Failed to delete alias record %s: %s\n",
745 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
746 ldb_errstring(state->sam_ldb)));
747 return NT_STATUS_INTERNAL_DB_CORRUPTION;
753 static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
754 struct samsync_ldb_state *state,
755 struct creds_CredentialState *creds,
756 enum netr_SamDatabaseID database,
757 struct netr_DELTA_ENUM *delta)
759 uint32_t rid = delta->delta_id_union.rid;
760 struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
761 struct ldb_message *msg;
762 struct ldb_message **msgs;
764 const char *attrs[] = { NULL };
767 msg = ldb_msg_new(mem_ctx);
769 return NT_STATUS_NO_MEMORY;
772 /* search for the alias, by rid */
773 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
774 "(&(objectClass=group)(objectSid=%s))",
775 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
778 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
779 return NT_STATUS_INTERNAL_DB_CORRUPTION;
780 } else if (ret == 0) {
781 return NT_STATUS_NO_SUCH_GROUP;
782 } else if (ret > 1) {
783 DEBUG(0, ("More than one group/alias with SID: %s\n",
784 dom_sid_string(mem_ctx,
785 dom_sid_add_rid(mem_ctx,
786 state->dom_sid[database],
788 return NT_STATUS_INTERNAL_DB_CORRUPTION;
790 msg->dn = talloc_steal(msg, msgs[0]->dn);
795 for (i=0; i<alias_member->sids.num_sids; i++) {
796 struct ldb_dn *alias_member_dn;
797 /* search for members, in the top basedn (normal users are builtin aliases) */
798 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
800 ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid));
803 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
804 return NT_STATUS_INTERNAL_DB_CORRUPTION;
805 } else if (ret == 0) {
807 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
808 alias_member->sids.sids[i].sid,
810 if (!NT_STATUS_IS_OK(nt_status)) {
813 } else if (ret > 1) {
814 return NT_STATUS_INTERNAL_DB_CORRUPTION;
816 alias_member_dn = msgs[0]->dn;
818 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, alias_member_dn));
823 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
825 DEBUG(0,("Failed to modify group record %s: %s\n",
826 ldb_dn_linearize(mem_ctx, msg->dn),
827 ldb_errstring(state->sam_ldb)));
828 return NT_STATUS_INTERNAL_DB_CORRUPTION;
834 static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
835 struct samsync_ldb_state *state,
836 struct creds_CredentialState *creds,
837 enum netr_SamDatabaseID database,
838 struct netr_DELTA_ENUM *delta)
840 struct dom_sid *sid = delta->delta_id_union.sid;
841 struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
843 struct ldb_message *msg;
844 struct ldb_message **msgs;
845 struct ldb_dn *privilege_dn;
847 const char *attrs[] = { NULL };
850 msg = ldb_msg_new(mem_ctx);
852 return NT_STATUS_NO_MEMORY;
855 /* search for the account, by sid, in the top basedn */
856 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
857 "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, sid));
860 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
861 return NT_STATUS_INTERNAL_DB_CORRUPTION;
862 } else if (ret == 0) {
864 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
867 privilege_dn = talloc_steal(msg, privilege_dn);
868 if (!NT_STATUS_IS_OK(nt_status)) {
871 } else if (ret > 1) {
872 DEBUG(0, ("More than one account with SID: %s\n",
873 dom_sid_string(mem_ctx, sid)));
874 return NT_STATUS_INTERNAL_DB_CORRUPTION;
876 privilege_dn = talloc_steal(msg, msgs[0]->dn);
879 msg->dn = privilege_dn;
881 for (i=0; i< account->privilege_entries; i++) {
882 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "privilege",
883 account->privilege_name[i].string);
886 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
888 DEBUG(0,("Failed to modify privilege record %s\n",
889 ldb_dn_linearize(mem_ctx, msg->dn)));
890 return NT_STATUS_INTERNAL_DB_CORRUPTION;
896 static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
897 struct samsync_ldb_state *state,
898 struct creds_CredentialState *creds,
899 enum netr_SamDatabaseID database,
900 struct netr_DELTA_ENUM *delta)
902 struct dom_sid *sid = delta->delta_id_union.sid;
904 struct ldb_message *msg;
905 struct ldb_message **msgs;
907 const char *attrs[] = { NULL };
909 msg = ldb_msg_new(mem_ctx);
911 return NT_STATUS_NO_MEMORY;
914 /* search for the account, by sid, in the top basedn */
915 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
917 ldap_encode_ndr_dom_sid(mem_ctx, sid));
920 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
921 return NT_STATUS_INTERNAL_DB_CORRUPTION;
922 } else if (ret == 0) {
923 return NT_STATUS_NO_SUCH_USER;
924 } else if (ret > 1) {
925 DEBUG(0, ("More than one account with SID: %s\n",
926 dom_sid_string(mem_ctx, sid)));
927 return NT_STATUS_INTERNAL_DB_CORRUPTION;
929 msg->dn = talloc_steal(msg, msgs[0]->dn);
932 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
935 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
937 DEBUG(0,("Failed to modify privilege record %s\n",
938 ldb_dn_linearize(mem_ctx, msg->dn)));
939 return NT_STATUS_INTERNAL_DB_CORRUPTION;
945 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,
947 struct creds_CredentialState *creds,
948 enum netr_SamDatabaseID database,
949 struct netr_DELTA_ENUM *delta,
952 NTSTATUS nt_status = NT_STATUS_OK;
953 struct samsync_ldb_state *state = private;
955 *error_string = NULL;
956 switch (delta->delta_type) {
957 case NETR_DELTA_DOMAIN:
959 nt_status = samsync_ldb_handle_domain(mem_ctx,
966 case NETR_DELTA_USER:
968 nt_status = samsync_ldb_handle_user(mem_ctx,
975 case NETR_DELTA_DELETE_USER:
977 nt_status = samsync_ldb_delete_user(mem_ctx,
984 case NETR_DELTA_GROUP:
986 nt_status = samsync_ldb_handle_group(mem_ctx,
993 case NETR_DELTA_DELETE_GROUP:
995 nt_status = samsync_ldb_delete_group(mem_ctx,
1002 case NETR_DELTA_GROUP_MEMBER:
1004 nt_status = samsync_ldb_handle_group_member(mem_ctx,
1011 case NETR_DELTA_ALIAS:
1013 nt_status = samsync_ldb_handle_alias(mem_ctx,
1020 case NETR_DELTA_DELETE_ALIAS:
1022 nt_status = samsync_ldb_delete_alias(mem_ctx,
1029 case NETR_DELTA_ALIAS_MEMBER:
1031 nt_status = samsync_ldb_handle_alias_member(mem_ctx,
1038 case NETR_DELTA_ACCOUNT:
1040 nt_status = samsync_ldb_handle_account(mem_ctx,
1047 case NETR_DELTA_DELETE_ACCOUNT:
1049 nt_status = samsync_ldb_delete_account(mem_ctx,
1057 /* Can't dump them all right now */
1063 static NTSTATUS libnet_samsync_ldb_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1066 struct libnet_SamSync r2;
1067 struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
1070 return NT_STATUS_NO_MEMORY;
1073 state->secrets = NULL;
1074 state->trusted_domains = NULL;
1076 state->sam_ldb = samdb_connect(state);
1080 r2.error_string = NULL;
1081 r2.delta_fn = libnet_samsync_ldb_fn;
1083 r2.machine_account = NULL; /* TODO: Create a machine account, fill this in, and the delete it */
1084 nt_status = libnet_SamSync_netlogon(ctx, state, &r2);
1085 r->error_string = r2.error_string;
1087 if (!NT_STATUS_IS_OK(nt_status)) {
1097 static NTSTATUS libnet_samsync_ldb_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1100 struct libnet_samsync_ldb r2;
1101 r2.level = LIBNET_SAMSYNC_LDB_NETLOGON;
1102 r2.error_string = NULL;
1103 nt_status = libnet_samsync_ldb(ctx, mem_ctx, &r2);
1104 r->error_string = r2.error_string;
1109 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1112 case LIBNET_SAMSYNC_LDB_GENERIC:
1113 return libnet_samsync_ldb_generic(ctx, mem_ctx, r);
1114 case LIBNET_SAMSYNC_LDB_NETLOGON:
1115 return libnet_samsync_ldb_netlogon(ctx, mem_ctx, r);
1118 return NT_STATUS_INVALID_LEVEL;