waf: Fix parsing of cross-answers file in case answer includes a colon
[Samba.git] / source4 / libnet / libnet_samsync_ldb.c
blobf3a45b8625724250299c0f71082a5b366f883a35
1 /*
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 3 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, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "libnet/libnet.h"
27 #include "libcli/ldap/ldap_ndr.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "auth/auth.h"
30 #include "../lib/util/util_ldb.h"
31 #include "librpc/gen_ndr/ndr_misc.h"
32 #include "ldb_wrap.h"
33 #include "libcli/security/security.h"
34 #include "param/param.h"
36 struct samsync_ldb_secret {
37 struct samsync_ldb_secret *prev, *next;
38 DATA_BLOB secret;
39 char *name;
40 NTTIME mtime;
43 struct samsync_ldb_trusted_domain {
44 struct samsync_ldb_trusted_domain *prev, *next;
45 struct dom_sid *sid;
46 char *name;
49 struct samsync_ldb_state {
50 /* Values from the LSA lookup */
51 const struct libnet_SamSync_state *samsync_state;
53 struct dom_sid *dom_sid[3];
54 struct ldb_context *sam_ldb, *remote_ldb, *pdb;
55 struct ldb_dn *base_dn[3];
56 struct samsync_ldb_secret *secrets;
57 struct samsync_ldb_trusted_domain *trusted_domains;
60 /* This wrapper is needed for the "ADD_OR_DEL" macros */
61 static int samdb_msg_add_string(struct ldb_context *sam_ldb,
62 TALLOC_CTX *mem_ctx, struct ldb_message *msg,
63 const char *attr_name, const char *str)
65 return ldb_msg_add_string(msg, attr_name, str);
68 static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,
69 struct samsync_ldb_state *state,
70 struct dom_sid *sid,
71 struct ldb_dn **fsp_dn,
72 char **error_string)
74 const char *sidstr = dom_sid_string(mem_ctx, sid);
75 /* We assume that ForeignSecurityPrincipals are under the BASEDN of the main domain */
76 struct ldb_dn *basedn = samdb_search_dn(state->sam_ldb, mem_ctx,
77 state->base_dn[SAM_DATABASE_DOMAIN],
78 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
79 struct ldb_message *msg;
80 int ret;
82 if (!sidstr) {
83 return NT_STATUS_NO_MEMORY;
86 if (basedn == NULL) {
87 *error_string = talloc_asprintf(mem_ctx,
88 "Failed to find DN for "
89 "ForeignSecurityPrincipal container under %s",
90 ldb_dn_get_linearized(state->base_dn[SAM_DATABASE_DOMAIN]));
91 return NT_STATUS_INTERNAL_DB_CORRUPTION;
94 msg = ldb_msg_new(mem_ctx);
95 if (msg == NULL) {
96 return NT_STATUS_NO_MEMORY;
99 /* add core elements to the ldb_message for the alias */
100 msg->dn = basedn;
101 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
102 return NT_STATUS_UNSUCCESSFUL;
104 ldb_msg_add_string(msg, "objectClass", "foreignSecurityPrincipal");
106 *fsp_dn = msg->dn;
108 /* create the alias */
109 ret = ldb_add(state->sam_ldb, msg);
110 if (ret != LDB_SUCCESS) {
111 *error_string = talloc_asprintf(mem_ctx, "Failed to create foreignSecurityPrincipal "
112 "record %s: %s",
113 ldb_dn_get_linearized(msg->dn),
114 ldb_errstring(state->sam_ldb));
115 return NT_STATUS_INTERNAL_DB_CORRUPTION;
117 return NT_STATUS_OK;
120 static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
121 struct samsync_ldb_state *state,
122 enum netr_SamDatabaseID database,
123 struct netr_DELTA_ENUM *delta,
124 char **error_string)
126 struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;
127 const char *domain_name = domain->domain_name.string;
128 struct ldb_message *msg;
129 int ret;
131 msg = ldb_msg_new(mem_ctx);
132 if (msg == NULL) {
133 return NT_STATUS_NO_MEMORY;
136 if (database == SAM_DATABASE_DOMAIN) {
137 struct ldb_dn *partitions_basedn;
138 const char *domain_attrs[] = {"nETBIOSName", "nCName", NULL};
139 struct ldb_message **msgs_domain;
140 int ret_domain;
142 partitions_basedn = samdb_partitions_dn(state->sam_ldb, mem_ctx);
144 ret_domain = gendb_search(state->sam_ldb, mem_ctx, partitions_basedn, &msgs_domain, domain_attrs,
145 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
146 domain_name);
147 if (ret_domain == -1) {
148 *error_string = talloc_asprintf(mem_ctx, "gendb_search for domain failed: %s", ldb_errstring(state->sam_ldb));
149 return NT_STATUS_INTERNAL_DB_CORRUPTION;
152 if (ret_domain != 1) {
153 *error_string = talloc_asprintf(mem_ctx, "Failed to find existing domain record for %s: %d results", domain_name,
154 ret_domain);
155 return NT_STATUS_NO_SUCH_DOMAIN;
158 state->base_dn[database] = samdb_result_dn(state->sam_ldb, state, msgs_domain[0], "nCName", NULL);
160 if (state->dom_sid[database]) {
161 /* Update the domain sid with the incoming
162 * domain (found on LSA pipe, database sid may
163 * be random) */
164 ret = samdb_msg_add_dom_sid(state->sam_ldb,
165 mem_ctx,
166 msg,
167 "objectSid",
168 state->dom_sid[database]);
169 if (ret != LDB_SUCCESS) {
170 return NT_STATUS_INTERNAL_ERROR;
172 } else {
173 /* Well, we will have to use the one from the database */
174 state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state,
175 state->base_dn[database],
176 "objectSid", NULL);
177 if (state->dom_sid[database] == NULL) {
178 return NT_STATUS_INTERNAL_ERROR;
182 if (state->samsync_state->domain_guid) {
183 struct ldb_val v;
184 NTSTATUS status;
185 status = GUID_to_ndr_blob(state->samsync_state->domain_guid, msg, &v);
186 if (!NT_STATUS_IS_OK(status)) {
187 *error_string = talloc_asprintf(mem_ctx, "ndr_push of domain GUID failed!");
188 return status;
191 ret = ldb_msg_add_value(msg, "objectGUID", &v, NULL);
192 if (ret != LDB_SUCCESS) {
193 return NT_STATUS_INTERNAL_ERROR;
196 } else if (database == SAM_DATABASE_BUILTIN) {
197 /* work out the builtin_dn - useful for so many calls its worth
198 fetching here */
199 const char *dnstring = samdb_search_string(state->sam_ldb, mem_ctx, NULL,
200 "distinguishedName", "objectClass=builtinDomain");
201 state->base_dn[database] = ldb_dn_new(state, state->sam_ldb, dnstring);
202 if ( ! ldb_dn_validate(state->base_dn[database])) {
203 return NT_STATUS_INTERNAL_ERROR;
205 } else {
206 /* PRIVs DB */
207 return NT_STATUS_INVALID_PARAMETER;
210 msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
211 if (!msg->dn) {
212 return NT_STATUS_NO_MEMORY;
215 ldb_msg_add_string(msg, "oEMInformation",
216 domain->oem_information.string);
218 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
219 msg, "forceLogoff", domain->force_logoff_time);
221 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
222 msg, "minPwdLen", domain->min_password_length);
224 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
225 msg, "maxPwdAge", domain->max_password_age);
227 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
228 msg, "minPwdAge", domain->min_password_age);
230 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
231 msg, "pwdHistoryLength", domain->password_history_length);
233 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
234 msg, "modifiedCount",
235 domain->sequence_num);
237 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
238 msg, "creationTime", domain->domain_create_time);
240 /* TODO: Account lockout, password properties */
242 ret = dsdb_replace(state->sam_ldb, msg, 0);
243 if (ret != LDB_SUCCESS) {
244 *error_string = talloc_asprintf(mem_ctx,
245 "Failed to modify domain record %s: %s",
246 ldb_dn_get_linearized(msg->dn),
247 ldb_errstring(state->sam_ldb));
248 return NT_STATUS_INTERNAL_DB_CORRUPTION;
250 return NT_STATUS_OK;
253 static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
254 struct samsync_ldb_state *state,
255 enum netr_SamDatabaseID database,
256 struct netr_DELTA_ENUM *delta,
257 char **error_string)
259 uint32_t rid = delta->delta_id_union.rid;
260 struct netr_DELTA_USER *user = delta->delta_union.user;
261 const char *container, *obj_class;
262 char *cn_name;
263 int cn_name_len;
264 const struct dom_sid *user_sid;
265 struct ldb_message *msg;
266 struct ldb_message **msgs;
267 struct ldb_message **remote_msgs = NULL;
268 unsigned int i;
269 int ret;
270 uint32_t acb;
271 bool add = false;
272 const char *attrs[] = { NULL };
273 /* we may change this to a global search, then fill in only the things not in ldap later */
274 const char *remote_attrs[] = { "userPrincipalName", "servicePrincipalName",
275 "msDS-KeyVersionNumber", "objectGUID", NULL};
277 user_sid = dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid);
278 if (!user_sid) {
279 return NT_STATUS_NO_MEMORY;
282 msg = ldb_msg_new(mem_ctx);
283 if (msg == NULL) {
284 return NT_STATUS_NO_MEMORY;
287 msg->dn = NULL;
288 /* search for the user, by rid */
289 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
290 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
291 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
293 if (ret == -1) {
294 *error_string = talloc_asprintf(mem_ctx, "LDB for user %s failed: %s",
295 dom_sid_string(mem_ctx, user_sid),
296 ldb_errstring(state->sam_ldb));
297 return NT_STATUS_INTERNAL_DB_CORRUPTION;
298 } else if (ret == 0) {
299 add = true;
300 } else if (ret > 1) {
301 *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s in local LDB",
302 dom_sid_string(mem_ctx, user_sid));
303 return NT_STATUS_INTERNAL_DB_CORRUPTION;
304 } else {
305 msg->dn = msgs[0]->dn;
306 talloc_steal(msg, msgs[0]->dn);
309 /* and do the same on the remote database */
310 if (state->remote_ldb) {
311 ret = gendb_search(state->remote_ldb, mem_ctx, state->base_dn[database],
312 &remote_msgs, remote_attrs, "(&(objectClass=user)(objectSid=%s))",
313 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
315 if (ret == -1) {
316 *error_string = talloc_asprintf(mem_ctx, "remote LDAP for user %s failed: %s",
317 dom_sid_string(mem_ctx, user_sid),
318 ldb_errstring(state->remote_ldb));
319 return NT_STATUS_INTERNAL_DB_CORRUPTION;
320 } else if (ret == 0) {
321 *error_string = talloc_asprintf(mem_ctx, "User exists in samsync but not in remote LDAP domain! (base: %s, SID: %s)",
322 ldb_dn_get_linearized(state->base_dn[database]),
323 dom_sid_string(mem_ctx, user_sid));
324 return NT_STATUS_NO_SUCH_USER;
325 } else if (ret > 1) {
326 *error_string = talloc_asprintf(mem_ctx, "More than one user in remote LDAP domain with SID: %s",
327 dom_sid_string(mem_ctx, user_sid));
328 return NT_STATUS_INTERNAL_DB_CORRUPTION;
330 /* Try to put things in the same location as the remote server */
331 } else if (add) {
332 msg->dn = talloc_steal(msg, remote_msgs[0]->dn);
336 cn_name = talloc_strdup(mem_ctx, user->account_name.string);
337 NT_STATUS_HAVE_NO_MEMORY(cn_name);
338 cn_name_len = strlen(cn_name);
340 #define ADD_OR_DEL(type, attrib, field) do { \
341 if (user->field) { \
342 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
343 attrib, user->field); \
344 } else if (!add) { \
345 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
346 attrib); \
348 } while (0);
350 ADD_OR_DEL(string, "samAccountName", account_name.string);
351 ADD_OR_DEL(string, "displayName", full_name.string);
353 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
354 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
355 return NT_STATUS_NO_MEMORY;
358 ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
359 ADD_OR_DEL(string, "homeDirectory", home_directory.string);
360 ADD_OR_DEL(string, "homeDrive", home_drive.string);
361 ADD_OR_DEL(string, "scriptPath", logon_script.string);
362 ADD_OR_DEL(string, "description", description.string);
363 ADD_OR_DEL(string, "userWorkstations", workstations.string);
365 ADD_OR_DEL(uint64, "lastLogon", last_logon);
366 ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
368 if (samdb_msg_add_logon_hours(state->sam_ldb, mem_ctx, msg, "logonHours", &user->logon_hours) != 0) {
369 return NT_STATUS_NO_MEMORY;
372 ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
373 ADD_OR_DEL(uint, "logonCount", logon_count);
375 ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
376 ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
378 if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg,
379 "userAccountControl", user->acct_flags) != 0) {
380 return NT_STATUS_NO_MEMORY;
383 if (user->lm_password_present) {
384 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
385 "dBCSPwd", &user->lmpassword);
386 } else if (!add) {
387 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
388 "dBCSPwd");
390 if (user->nt_password_present) {
391 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
392 "unicodePwd", &user->ntpassword);
393 } else if (!add) {
394 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
395 "unicodePwd");
398 ADD_OR_DEL(string, "comment", comment.string);
400 if (samdb_msg_add_parameters(state->sam_ldb, mem_ctx, msg, "userParameters", &user->parameters) != 0) {
401 return NT_STATUS_NO_MEMORY;
404 ADD_OR_DEL(uint, "countryCode", country_code);
405 ADD_OR_DEL(uint, "codePage", code_page);
407 ADD_OR_DEL(string, "profilePath", profile_path.string);
409 #undef ADD_OR_DEL
411 for (i=0; remote_attrs[i]; i++) {
412 struct ldb_message_element *el = ldb_msg_find_element(remote_msgs[0], remote_attrs[i]);
413 if (!el) {
414 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
415 remote_attrs[i]);
416 } else {
417 ldb_msg_add(msg, el, LDB_FLAG_MOD_REPLACE);
421 acb = user->acct_flags;
422 if (acb & (ACB_WSTRUST)) {
423 cn_name[cn_name_len - 1] = '\0';
424 container = "Computers";
425 obj_class = "computer";
427 } else if (acb & ACB_SVRTRUST) {
428 if (cn_name[cn_name_len - 1] != '$') {
429 return NT_STATUS_FOOBAR;
431 cn_name[cn_name_len - 1] = '\0';
432 container = "Domain Controllers";
433 obj_class = "computer";
434 } else {
435 container = "Users";
436 obj_class = "user";
438 if (add) {
439 ldb_msg_add_string(msg, "objectClass", obj_class);
440 if (!msg->dn) {
441 msg->dn = ldb_dn_copy(mem_ctx, state->base_dn[database]);
442 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container);
443 if (!msg->dn) {
444 return NT_STATUS_NO_MEMORY;
448 ret = ldb_add(state->sam_ldb, msg);
449 if (ret != LDB_SUCCESS) {
450 struct ldb_dn *first_try_dn = msg->dn;
451 /* Try again with the default DN */
452 if (!remote_msgs) {
453 *error_string = talloc_asprintf(mem_ctx, "Failed to create user record. Tried %s: %s",
454 ldb_dn_get_linearized(first_try_dn),
455 ldb_errstring(state->sam_ldb));
456 return NT_STATUS_INTERNAL_DB_CORRUPTION;
457 } else {
458 msg->dn = talloc_steal(msg, remote_msgs[0]->dn);
459 ret = ldb_add(state->sam_ldb, msg);
460 if (ret != LDB_SUCCESS) {
461 *error_string = talloc_asprintf(mem_ctx, "Failed to create user record. Tried both %s and %s: %s",
462 ldb_dn_get_linearized(first_try_dn),
463 ldb_dn_get_linearized(msg->dn),
464 ldb_errstring(state->sam_ldb));
465 return NT_STATUS_INTERNAL_DB_CORRUPTION;
469 } else {
470 ret = dsdb_replace(state->sam_ldb, msg, 0);
471 if (ret != LDB_SUCCESS) {
472 *error_string = talloc_asprintf(mem_ctx, "Failed to modify user record %s: %s",
473 ldb_dn_get_linearized(msg->dn),
474 ldb_errstring(state->sam_ldb));
475 return NT_STATUS_INTERNAL_DB_CORRUPTION;
479 return NT_STATUS_OK;
482 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
483 struct samsync_ldb_state *state,
484 enum netr_SamDatabaseID database,
485 struct netr_DELTA_ENUM *delta,
486 char **error_string)
488 uint32_t rid = delta->delta_id_union.rid;
489 struct ldb_message **msgs;
490 int ret;
491 const char *attrs[] = { NULL };
493 /* search for the user, by rid */
494 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
495 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
496 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
498 if (ret == -1) {
499 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
500 return NT_STATUS_INTERNAL_DB_CORRUPTION;
501 } else if (ret == 0) {
502 return NT_STATUS_NO_SUCH_USER;
503 } else if (ret > 1) {
504 *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s",
505 dom_sid_string(mem_ctx,
506 dom_sid_add_rid(mem_ctx,
507 state->dom_sid[database],
508 rid)));
509 return NT_STATUS_INTERNAL_DB_CORRUPTION;
512 ret = ldb_delete(state->sam_ldb, msgs[0]->dn);
513 if (ret != LDB_SUCCESS) {
514 *error_string = talloc_asprintf(mem_ctx, "Failed to delete user record %s: %s",
515 ldb_dn_get_linearized(msgs[0]->dn),
516 ldb_errstring(state->sam_ldb));
517 return NT_STATUS_INTERNAL_DB_CORRUPTION;
520 return NT_STATUS_OK;
523 static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
524 struct samsync_ldb_state *state,
525 enum netr_SamDatabaseID database,
526 struct netr_DELTA_ENUM *delta,
527 char **error_string)
529 uint32_t rid = delta->delta_id_union.rid;
530 struct netr_DELTA_GROUP *group = delta->delta_union.group;
531 const char *container, *obj_class;
532 const char *cn_name;
534 struct ldb_message *msg;
535 struct ldb_message **msgs;
536 int ret;
537 bool add = false;
538 const char *attrs[] = { NULL };
540 msg = ldb_msg_new(mem_ctx);
541 if (msg == NULL) {
542 return NT_STATUS_NO_MEMORY;
545 /* search for the group, by rid */
546 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
547 "(&(objectClass=group)(objectSid=%s))",
548 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
550 if (ret == -1) {
551 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
552 return NT_STATUS_INTERNAL_DB_CORRUPTION;
553 } else if (ret == 0) {
554 add = true;
555 } else if (ret > 1) {
556 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
557 dom_sid_string(mem_ctx,
558 dom_sid_add_rid(mem_ctx,
559 state->dom_sid[database],
560 rid)));
561 return NT_STATUS_INTERNAL_DB_CORRUPTION;
562 } else {
563 msg->dn = talloc_steal(msg, msgs[0]->dn);
566 cn_name = group->group_name.string;
568 #define ADD_OR_DEL(type, attrib, field) do { \
569 if (group->field) { \
570 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
571 attrib, group->field); \
572 } else if (!add) { \
573 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
574 attrib); \
576 } while (0);
578 ADD_OR_DEL(string, "samAccountName", group_name.string);
580 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
581 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
582 return NT_STATUS_NO_MEMORY;
585 ADD_OR_DEL(string, "description", description.string);
587 #undef ADD_OR_DEL
589 container = "Users";
590 obj_class = "group";
592 if (add) {
593 ldb_msg_add_string(msg, "objectClass", obj_class);
594 msg->dn = ldb_dn_copy(mem_ctx, state->base_dn[database]);
595 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container);
596 if (!msg->dn) {
597 return NT_STATUS_NO_MEMORY;
600 ret = ldb_add(state->sam_ldb, msg);
601 if (ret != LDB_SUCCESS) {
602 *error_string = talloc_asprintf(mem_ctx, "Failed to create group record %s: %s",
603 ldb_dn_get_linearized(msg->dn),
604 ldb_errstring(state->sam_ldb));
605 return NT_STATUS_INTERNAL_DB_CORRUPTION;
607 } else {
608 ret = dsdb_replace(state->sam_ldb, msg, 0);
609 if (ret != LDB_SUCCESS) {
610 *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
611 ldb_dn_get_linearized(msg->dn),
612 ldb_errstring(state->sam_ldb));
613 return NT_STATUS_INTERNAL_DB_CORRUPTION;
617 return NT_STATUS_OK;
620 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
621 struct samsync_ldb_state *state,
622 enum netr_SamDatabaseID database,
623 struct netr_DELTA_ENUM *delta,
624 char **error_string)
626 uint32_t rid = delta->delta_id_union.rid;
627 struct ldb_message **msgs;
628 int ret;
629 const char *attrs[] = { NULL };
631 /* search for the group, by rid */
632 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
633 "(&(objectClass=group)(objectSid=%s))",
634 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
636 if (ret == -1) {
637 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
638 return NT_STATUS_INTERNAL_DB_CORRUPTION;
639 } else if (ret == 0) {
640 return NT_STATUS_NO_SUCH_GROUP;
641 } else if (ret > 1) {
642 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
643 dom_sid_string(mem_ctx,
644 dom_sid_add_rid(mem_ctx,
645 state->dom_sid[database],
646 rid)));
647 return NT_STATUS_INTERNAL_DB_CORRUPTION;
650 ret = ldb_delete(state->sam_ldb, msgs[0]->dn);
651 if (ret != LDB_SUCCESS) {
652 *error_string = talloc_asprintf(mem_ctx, "Failed to delete group record %s: %s",
653 ldb_dn_get_linearized(msgs[0]->dn),
654 ldb_errstring(state->sam_ldb));
655 return NT_STATUS_INTERNAL_DB_CORRUPTION;
658 return NT_STATUS_OK;
661 static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
662 struct samsync_ldb_state *state,
663 enum netr_SamDatabaseID database,
664 struct netr_DELTA_ENUM *delta,
665 char **error_string)
667 uint32_t rid = delta->delta_id_union.rid;
668 struct netr_DELTA_GROUP_MEMBER *delta_group_member = delta->delta_union.group_member;
669 struct ldb_message *msg;
670 struct ldb_message **msgs;
671 int ret;
672 const char *attrs[] = { NULL };
673 const char *str_dn;
674 uint32_t i;
676 msg = ldb_msg_new(mem_ctx);
677 if (msg == NULL) {
678 return NT_STATUS_NO_MEMORY;
681 /* search for the group, by rid */
682 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
683 "(&(objectClass=group)(objectSid=%s))",
684 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
686 if (ret == -1) {
687 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
688 return NT_STATUS_INTERNAL_DB_CORRUPTION;
689 } else if (ret == 0) {
690 return NT_STATUS_NO_SUCH_GROUP;
691 } else if (ret > 1) {
692 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
693 dom_sid_string(mem_ctx,
694 dom_sid_add_rid(mem_ctx,
695 state->dom_sid[database],
696 rid)));
697 return NT_STATUS_INTERNAL_DB_CORRUPTION;
698 } else {
699 msg->dn = talloc_steal(msg, msgs[0]->dn);
702 talloc_free(msgs);
704 for (i=0; i<delta_group_member->num_rids; i++) {
705 /* search for the group, by rid */
706 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
707 "(&(objectClass=user)(objectSid=%s))",
708 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], delta_group_member->rids[i])));
710 if (ret == -1) {
711 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
712 return NT_STATUS_INTERNAL_DB_CORRUPTION;
713 } else if (ret == 0) {
714 return NT_STATUS_NO_SUCH_USER;
715 } else if (ret > 1) {
716 return NT_STATUS_INTERNAL_DB_CORRUPTION;
717 } else {
718 str_dn = ldb_dn_alloc_linearized(msg, msgs[0]->dn);
719 NT_STATUS_HAVE_NO_MEMORY(str_dn);
720 ret = ldb_msg_add_string(msg, "member", str_dn);
721 if (ret != LDB_SUCCESS) return NT_STATUS_NO_MEMORY;
724 talloc_free(msgs);
727 ret = dsdb_replace(state->sam_ldb, msg, 0);
728 if (ret != LDB_SUCCESS) {
729 *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
730 ldb_dn_get_linearized(msg->dn),
731 ldb_errstring(state->sam_ldb));
732 return NT_STATUS_INTERNAL_DB_CORRUPTION;
735 return NT_STATUS_OK;
738 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
739 struct samsync_ldb_state *state,
740 enum netr_SamDatabaseID database,
741 struct netr_DELTA_ENUM *delta,
742 char **error_string)
744 uint32_t rid = delta->delta_id_union.rid;
745 struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
746 const char *container, *obj_class;
747 const char *cn_name;
749 struct ldb_message *msg;
750 struct ldb_message **msgs;
751 int ret;
752 bool add = false;
753 const char *attrs[] = { NULL };
755 msg = ldb_msg_new(mem_ctx);
756 if (msg == NULL) {
757 return NT_STATUS_NO_MEMORY;
760 /* search for the alias, by rid */
761 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
762 "(&(objectClass=group)(objectSid=%s))",
763 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
765 if (ret == -1) {
766 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
767 return NT_STATUS_INTERNAL_DB_CORRUPTION;
768 } else if (ret == 0) {
769 add = true;
770 } else if (ret > 1) {
771 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
772 dom_sid_string(mem_ctx,
773 dom_sid_add_rid(mem_ctx,
774 state->dom_sid[database],
775 rid)));
776 return NT_STATUS_INTERNAL_DB_CORRUPTION;
777 } else {
778 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
781 cn_name = alias->alias_name.string;
783 #define ADD_OR_DEL(type, attrib, field) do { \
784 if (alias->field) { \
785 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
786 attrib, alias->field); \
787 } else if (!add) { \
788 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
789 attrib); \
791 } while (0);
793 ADD_OR_DEL(string, "samAccountName", alias_name.string);
795 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
796 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
797 return NT_STATUS_NO_MEMORY;
800 ADD_OR_DEL(string, "description", description.string);
802 #undef ADD_OR_DEL
804 samdb_msg_add_uint(state->sam_ldb, mem_ctx, msg, "groupType", 0x80000004);
806 container = "Users";
807 obj_class = "group";
809 if (add) {
810 ldb_msg_add_string(msg, "objectClass", obj_class);
811 msg->dn = ldb_dn_copy(mem_ctx, state->base_dn[database]);
812 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container);
813 if (!msg->dn) {
814 return NT_STATUS_NO_MEMORY;
817 ret = ldb_add(state->sam_ldb, msg);
818 if (ret != LDB_SUCCESS) {
819 *error_string = talloc_asprintf(mem_ctx, "Failed to create alias record %s: %s",
820 ldb_dn_get_linearized(msg->dn),
821 ldb_errstring(state->sam_ldb));
822 return NT_STATUS_INTERNAL_DB_CORRUPTION;
824 } else {
825 ret = dsdb_replace(state->sam_ldb, msg, 0);
826 if (ret != LDB_SUCCESS) {
827 *error_string = talloc_asprintf(mem_ctx, "Failed to modify alias record %s: %s",
828 ldb_dn_get_linearized(msg->dn),
829 ldb_errstring(state->sam_ldb));
830 return NT_STATUS_INTERNAL_DB_CORRUPTION;
834 return NT_STATUS_OK;
837 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
838 struct samsync_ldb_state *state,
839 enum netr_SamDatabaseID database,
840 struct netr_DELTA_ENUM *delta,
841 char **error_string)
843 uint32_t rid = delta->delta_id_union.rid;
844 struct ldb_message **msgs;
845 int ret;
846 const char *attrs[] = { NULL };
848 /* search for the alias, by rid */
849 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
850 "(&(objectClass=group)(objectSid=%s))",
851 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
853 if (ret == -1) {
854 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
855 return NT_STATUS_INTERNAL_DB_CORRUPTION;
856 } else if (ret == 0) {
857 return NT_STATUS_NO_SUCH_ALIAS;
858 } else if (ret > 1) {
859 return NT_STATUS_INTERNAL_DB_CORRUPTION;
862 ret = ldb_delete(state->sam_ldb, msgs[0]->dn);
863 if (ret != LDB_SUCCESS) {
864 *error_string = talloc_asprintf(mem_ctx, "Failed to delete alias record %s: %s",
865 ldb_dn_get_linearized(msgs[0]->dn),
866 ldb_errstring(state->sam_ldb));
867 return NT_STATUS_INTERNAL_DB_CORRUPTION;
870 return NT_STATUS_OK;
873 static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
874 struct samsync_ldb_state *state,
875 enum netr_SamDatabaseID database,
876 struct netr_DELTA_ENUM *delta,
877 char **error_string)
879 uint32_t rid = delta->delta_id_union.rid;
880 struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
881 struct ldb_message *msg;
882 struct ldb_message **msgs;
883 int ret;
884 const char *attrs[] = { NULL };
885 uint32_t i;
887 msg = ldb_msg_new(mem_ctx);
888 if (msg == NULL) {
889 return NT_STATUS_NO_MEMORY;
892 /* search for the alias, by rid */
893 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
894 "(&(objectClass=group)(objectSid=%s))",
895 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
897 if (ret == -1) {
898 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
899 return NT_STATUS_INTERNAL_DB_CORRUPTION;
900 } else if (ret == 0) {
901 return NT_STATUS_NO_SUCH_GROUP;
902 } else if (ret > 1) {
903 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
904 dom_sid_string(mem_ctx,
905 dom_sid_add_rid(mem_ctx,
906 state->dom_sid[database],
907 rid)));
908 return NT_STATUS_INTERNAL_DB_CORRUPTION;
909 } else {
910 msg->dn = talloc_steal(msg, msgs[0]->dn);
913 talloc_free(msgs);
915 for (i=0; i<alias_member->sids.num_sids; i++) {
916 struct ldb_dn *alias_member_dn;
917 const char *str_dn;
918 /* search for members, in the top basedn (normal users are builtin aliases) */
919 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
920 "(objectSid=%s)",
921 ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid));
923 if (ret == -1) {
924 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
925 return NT_STATUS_INTERNAL_DB_CORRUPTION;
926 } else if (ret == 0) {
927 NTSTATUS nt_status;
928 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
929 alias_member->sids.sids[i].sid,
930 &alias_member_dn,
931 error_string);
932 if (!NT_STATUS_IS_OK(nt_status)) {
933 return nt_status;
935 } else if (ret > 1) {
936 return NT_STATUS_INTERNAL_DB_CORRUPTION;
937 } else {
938 alias_member_dn = msgs[0]->dn;
940 str_dn = ldb_dn_alloc_linearized(msg, alias_member_dn);
941 NT_STATUS_HAVE_NO_MEMORY(str_dn);
942 ret = ldb_msg_add_string(msg, "member", str_dn);
943 if (ret != LDB_SUCCESS) return NT_STATUS_NO_MEMORY;
945 talloc_free(msgs);
948 ret = dsdb_replace(state->sam_ldb, msg, 0);
949 if (ret != LDB_SUCCESS) {
950 *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
951 ldb_dn_get_linearized(msg->dn),
952 ldb_errstring(state->sam_ldb));
953 return NT_STATUS_INTERNAL_DB_CORRUPTION;
956 return NT_STATUS_OK;
959 static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
960 struct samsync_ldb_state *state,
961 enum netr_SamDatabaseID database,
962 struct netr_DELTA_ENUM *delta,
963 char **error_string)
965 struct dom_sid *sid = delta->delta_id_union.sid;
966 struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
968 struct ldb_message *msg;
969 int ret;
970 uint32_t i;
971 char *dnstr, *sidstr;
973 msg = ldb_msg_new(mem_ctx);
974 if (msg == NULL) {
975 return NT_STATUS_NO_MEMORY;
978 sidstr = dom_sid_string(msg, sid);
979 if (sidstr == NULL) {
980 TALLOC_FREE(msg);
981 return NT_STATUS_NO_MEMORY;
984 dnstr = talloc_asprintf(msg, "sid=%s", sidstr);
985 if (dnstr == NULL) {
986 TALLOC_FREE(msg);
987 return NT_STATUS_NO_MEMORY;
990 msg->dn = ldb_dn_new(msg, state->pdb, dnstr);
991 if (msg->dn == NULL) {
992 TALLOC_FREE(msg);
993 return NT_STATUS_NO_MEMORY;
996 for (i=0; i< account->privilege_entries; i++) {
997 ldb_msg_add_string(msg, "privilege", account->privilege_name[i].string);
1000 ret = dsdb_replace(state->pdb, msg, 0);
1001 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1002 if (samdb_msg_add_dom_sid(state->pdb, msg, msg, "objectSid", sid) != LDB_SUCCESS) {
1003 talloc_free(msg);
1004 return NT_STATUS_NO_MEMORY;
1006 ldb_msg_add_string(msg, "comment", "added via samsync");
1007 ret = ldb_add(state->pdb, msg);
1010 if (ret != LDB_SUCCESS) {
1011 *error_string = talloc_asprintf(mem_ctx, "Failed to modify privilege record %s",
1012 ldb_dn_get_linearized(msg->dn));
1013 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1016 return NT_STATUS_OK;
1019 static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
1020 struct samsync_ldb_state *state,
1021 enum netr_SamDatabaseID database,
1022 struct netr_DELTA_ENUM *delta,
1023 char **error_string)
1025 struct dom_sid *sid = delta->delta_id_union.sid;
1027 struct ldb_message *msg;
1028 struct ldb_message **msgs;
1029 int ret;
1030 const char *attrs[] = { NULL };
1032 msg = ldb_msg_new(mem_ctx);
1033 if (msg == NULL) {
1034 return NT_STATUS_NO_MEMORY;
1037 /* search for the account, by sid, in the top basedn */
1038 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
1039 "(objectSid=%s)",
1040 ldap_encode_ndr_dom_sid(mem_ctx, sid));
1042 if (ret == -1) {
1043 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
1044 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1045 } else if (ret == 0) {
1046 return NT_STATUS_NO_SUCH_USER;
1047 } else if (ret > 1) {
1048 *error_string = talloc_asprintf(mem_ctx, "More than one account with SID: %s",
1049 dom_sid_string(mem_ctx, sid));
1050 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1051 } else {
1052 msg->dn = talloc_steal(msg, msgs[0]->dn);
1055 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
1056 "privilege");
1058 ret = dsdb_replace(state->sam_ldb, msg, 0);
1059 if (ret != LDB_SUCCESS) {
1060 *error_string = talloc_asprintf(mem_ctx, "Failed to modify privilege record %s",
1061 ldb_dn_get_linearized(msg->dn));
1062 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1065 return NT_STATUS_OK;
1068 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,
1069 void *private_data,
1070 enum netr_SamDatabaseID database,
1071 struct netr_DELTA_ENUM *delta,
1072 char **error_string)
1074 NTSTATUS nt_status = NT_STATUS_OK;
1075 struct samsync_ldb_state *state = talloc_get_type(private_data, struct samsync_ldb_state);
1077 *error_string = NULL;
1078 switch (delta->delta_type) {
1079 case NETR_DELTA_DOMAIN:
1081 nt_status = samsync_ldb_handle_domain(mem_ctx,
1082 state,
1083 database,
1084 delta,
1085 error_string);
1086 break;
1088 case NETR_DELTA_USER:
1090 nt_status = samsync_ldb_handle_user(mem_ctx,
1091 state,
1092 database,
1093 delta,
1094 error_string);
1095 break;
1097 case NETR_DELTA_DELETE_USER:
1099 nt_status = samsync_ldb_delete_user(mem_ctx,
1100 state,
1101 database,
1102 delta,
1103 error_string);
1104 break;
1106 case NETR_DELTA_GROUP:
1108 nt_status = samsync_ldb_handle_group(mem_ctx,
1109 state,
1110 database,
1111 delta,
1112 error_string);
1113 break;
1115 case NETR_DELTA_DELETE_GROUP:
1117 nt_status = samsync_ldb_delete_group(mem_ctx,
1118 state,
1119 database,
1120 delta,
1121 error_string);
1122 break;
1124 case NETR_DELTA_GROUP_MEMBER:
1126 nt_status = samsync_ldb_handle_group_member(mem_ctx,
1127 state,
1128 database,
1129 delta,
1130 error_string);
1131 break;
1133 case NETR_DELTA_ALIAS:
1135 nt_status = samsync_ldb_handle_alias(mem_ctx,
1136 state,
1137 database,
1138 delta,
1139 error_string);
1140 break;
1142 case NETR_DELTA_DELETE_ALIAS:
1144 nt_status = samsync_ldb_delete_alias(mem_ctx,
1145 state,
1146 database,
1147 delta,
1148 error_string);
1149 break;
1151 case NETR_DELTA_ALIAS_MEMBER:
1153 nt_status = samsync_ldb_handle_alias_member(mem_ctx,
1154 state,
1155 database,
1156 delta,
1157 error_string);
1158 break;
1160 case NETR_DELTA_ACCOUNT:
1162 nt_status = samsync_ldb_handle_account(mem_ctx,
1163 state,
1164 database,
1165 delta,
1166 error_string);
1167 break;
1169 case NETR_DELTA_DELETE_ACCOUNT:
1171 nt_status = samsync_ldb_delete_account(mem_ctx,
1172 state,
1173 database,
1174 delta,
1175 error_string);
1176 break;
1178 default:
1179 /* Can't dump them all right now */
1180 break;
1182 if (!NT_STATUS_IS_OK(nt_status) && !*error_string) {
1183 *error_string = talloc_asprintf(mem_ctx, "Failed to handle samsync delta: %s", nt_errstr(nt_status));
1185 return nt_status;
1188 static NTSTATUS libnet_samsync_ldb_init(TALLOC_CTX *mem_ctx,
1189 void *private_data,
1190 struct libnet_SamSync_state *samsync_state,
1191 char **error_string)
1193 struct samsync_ldb_state *state = talloc_get_type(private_data, struct samsync_ldb_state);
1194 const char *server = dcerpc_server_name(samsync_state->netlogon_pipe);
1195 char *ldap_url;
1197 state->samsync_state = samsync_state;
1199 ZERO_STRUCT(state->dom_sid);
1200 if (state->samsync_state->domain_sid) {
1201 state->dom_sid[SAM_DATABASE_DOMAIN] = dom_sid_dup(state, state->samsync_state->domain_sid);
1204 state->dom_sid[SAM_DATABASE_BUILTIN] = dom_sid_parse_talloc(state, SID_BUILTIN);
1206 if (state->samsync_state->realm) {
1207 if (!server || !*server) {
1208 /* huh? how do we not have a server name? */
1209 *error_string = talloc_strdup(mem_ctx, "No DCE/RPC server name available. How did we connect?");
1210 return NT_STATUS_INVALID_PARAMETER;
1212 ldap_url = talloc_asprintf(state, "ldap://%s", server);
1214 state->remote_ldb = ldb_wrap_connect(mem_ctx,
1215 NULL,
1216 state->samsync_state->machine_net_ctx->lp_ctx,
1217 ldap_url,
1218 NULL, state->samsync_state->machine_net_ctx->cred,
1220 if (!state->remote_ldb) {
1221 *error_string = talloc_asprintf(mem_ctx, "Failed to connect to remote LDAP server at %s (used to extract additional data in SamSync replication)", ldap_url);
1222 return NT_STATUS_NO_LOGON_SERVERS;
1224 } else {
1225 state->remote_ldb = NULL;
1227 return NT_STATUS_OK;
1230 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1232 NTSTATUS nt_status;
1233 struct libnet_SamSync r2;
1234 struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
1236 if (!state) {
1237 return NT_STATUS_NO_MEMORY;
1240 state->secrets = NULL;
1241 state->trusted_domains = NULL;
1243 state->sam_ldb = samdb_connect(mem_ctx,
1244 ctx->event_ctx,
1245 ctx->lp_ctx,
1246 r->in.session_info,
1248 if (!state->sam_ldb) {
1249 return NT_STATUS_INTERNAL_DB_ERROR;
1252 state->pdb = privilege_connect(mem_ctx,
1253 ctx->lp_ctx);
1254 if (!state->pdb) {
1255 return NT_STATUS_INTERNAL_DB_ERROR;
1258 r2.out.error_string = NULL;
1259 r2.in.binding_string = r->in.binding_string;
1260 r2.in.init_fn = libnet_samsync_ldb_init;
1261 r2.in.delta_fn = libnet_samsync_ldb_fn;
1262 r2.in.fn_ctx = state;
1263 r2.in.machine_account = NULL; /* TODO: Create a machine account, fill this in, and the delete it */
1264 nt_status = libnet_SamSync_netlogon(ctx, state, &r2);
1265 r->out.error_string = r2.out.error_string;
1266 talloc_steal(mem_ctx, r->out.error_string);
1268 if (!NT_STATUS_IS_OK(nt_status)) {
1269 talloc_free(state);
1270 return nt_status;
1272 talloc_free(state);
1273 return nt_status;