s3:net ads dns register: use "cluster addresses" option if configured (bug #7871)
[Samba/gebeck_regimport.git] / source4 / libnet / libnet_samsync_ldb.c
blob07e085edb131c8b27912bb50feb45c12572208f8
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 static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,
61 struct samsync_ldb_state *state,
62 struct dom_sid *sid,
63 struct ldb_dn **fsp_dn,
64 char **error_string)
66 const char *sidstr = dom_sid_string(mem_ctx, sid);
67 /* We assume that ForeignSecurityPrincipals are under the BASEDN of the main domain */
68 struct ldb_dn *basedn = samdb_search_dn(state->sam_ldb, mem_ctx,
69 state->base_dn[SAM_DATABASE_DOMAIN],
70 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
71 struct ldb_message *msg;
72 int ret;
74 if (!sidstr) {
75 return NT_STATUS_NO_MEMORY;
78 if (basedn == NULL) {
79 *error_string = talloc_asprintf(mem_ctx,
80 "Failed to find DN for "
81 "ForeignSecurityPrincipal container under %s",
82 ldb_dn_get_linearized(state->base_dn[SAM_DATABASE_DOMAIN]));
83 return NT_STATUS_INTERNAL_DB_CORRUPTION;
86 msg = ldb_msg_new(mem_ctx);
87 if (msg == NULL) {
88 return NT_STATUS_NO_MEMORY;
91 /* add core elements to the ldb_message for the alias */
92 msg->dn = basedn;
93 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
94 return NT_STATUS_UNSUCCESSFUL;
96 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
97 "objectClass",
98 "foreignSecurityPrincipal");
100 *fsp_dn = msg->dn;
102 /* create the alias */
103 ret = ldb_add(state->sam_ldb, msg);
104 if (ret != LDB_SUCCESS) {
105 *error_string = talloc_asprintf(mem_ctx, "Failed to create foreignSecurityPrincipal "
106 "record %s: %s",
107 ldb_dn_get_linearized(msg->dn),
108 ldb_errstring(state->sam_ldb));
109 return NT_STATUS_INTERNAL_DB_CORRUPTION;
111 return NT_STATUS_OK;
114 static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
115 struct samsync_ldb_state *state,
116 enum netr_SamDatabaseID database,
117 struct netr_DELTA_ENUM *delta,
118 char **error_string)
120 struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;
121 const char *domain_name = domain->domain_name.string;
122 struct ldb_message *msg;
123 int ret;
125 msg = ldb_msg_new(mem_ctx);
126 if (msg == NULL) {
127 return NT_STATUS_NO_MEMORY;
130 if (database == SAM_DATABASE_DOMAIN) {
131 struct ldb_dn *partitions_basedn;
132 const char *domain_attrs[] = {"nETBIOSName", "nCName", NULL};
133 struct ldb_message **msgs_domain;
134 int ret_domain;
136 partitions_basedn = samdb_partitions_dn(state->sam_ldb, mem_ctx);
138 ret_domain = gendb_search(state->sam_ldb, mem_ctx, partitions_basedn, &msgs_domain, domain_attrs,
139 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
140 domain_name);
141 if (ret_domain == -1) {
142 *error_string = talloc_asprintf(mem_ctx, "gendb_search for domain failed: %s", ldb_errstring(state->sam_ldb));
143 return NT_STATUS_INTERNAL_DB_CORRUPTION;
146 if (ret_domain != 1) {
147 *error_string = talloc_asprintf(mem_ctx, "Failed to find existing domain record for %s: %d results", domain_name,
148 ret_domain);
149 return NT_STATUS_NO_SUCH_DOMAIN;
152 state->base_dn[database] = samdb_result_dn(state->sam_ldb, state, msgs_domain[0], "nCName", NULL);
154 if (state->dom_sid[database]) {
155 /* Update the domain sid with the incoming
156 * domain (found on LSA pipe, database sid may
157 * be random) */
158 samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx,
159 msg, "objectSid", state->dom_sid[database]);
160 } else {
161 /* Well, we will have to use the one from the database */
162 state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state,
163 state->base_dn[database],
164 "objectSid", NULL);
167 if (state->samsync_state->domain_guid) {
168 struct ldb_val v;
169 NTSTATUS status;
170 status = GUID_to_ndr_blob(state->samsync_state->domain_guid, msg, &v);
171 if (!NT_STATUS_IS_OK(status)) {
172 *error_string = talloc_asprintf(mem_ctx, "ndr_push of domain GUID failed!");
173 return status;
176 ldb_msg_add_value(msg, "objectGUID", &v, NULL);
178 } else if (database == SAM_DATABASE_BUILTIN) {
179 /* work out the builtin_dn - useful for so many calls its worth
180 fetching here */
181 const char *dnstring = samdb_search_string(state->sam_ldb, mem_ctx, NULL,
182 "distinguishedName", "objectClass=builtinDomain");
183 state->base_dn[database] = ldb_dn_new(state, state->sam_ldb, dnstring);
184 if ( ! ldb_dn_validate(state->base_dn[database])) {
185 return NT_STATUS_INTERNAL_ERROR;
187 } else {
188 /* PRIVs DB */
189 return NT_STATUS_INVALID_PARAMETER;
192 msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
193 if (!msg->dn) {
194 return NT_STATUS_NO_MEMORY;
197 samdb_msg_add_string(state->sam_ldb, mem_ctx,
198 msg, "oEMInformation", domain->oem_information.string);
200 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
201 msg, "forceLogoff", domain->force_logoff_time);
203 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
204 msg, "minPwdLen", domain->min_password_length);
206 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
207 msg, "maxPwdAge", domain->max_password_age);
209 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
210 msg, "minPwdAge", domain->min_password_age);
212 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
213 msg, "pwdHistoryLength", domain->password_history_length);
215 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
216 msg, "modifiedCount",
217 domain->sequence_num);
219 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
220 msg, "creationTime", domain->domain_create_time);
222 /* TODO: Account lockout, password properties */
224 ret = dsdb_replace(state->sam_ldb, msg, 0);
225 if (ret != LDB_SUCCESS) {
226 *error_string = talloc_asprintf(mem_ctx,
227 "Failed to modify domain record %s: %s",
228 ldb_dn_get_linearized(msg->dn),
229 ldb_errstring(state->sam_ldb));
230 return NT_STATUS_INTERNAL_DB_CORRUPTION;
232 return NT_STATUS_OK;
235 static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
236 struct samsync_ldb_state *state,
237 enum netr_SamDatabaseID database,
238 struct netr_DELTA_ENUM *delta,
239 char **error_string)
241 uint32_t rid = delta->delta_id_union.rid;
242 struct netr_DELTA_USER *user = delta->delta_union.user;
243 const char *container, *obj_class;
244 char *cn_name;
245 int cn_name_len;
246 const struct dom_sid *user_sid;
247 struct ldb_message *msg;
248 struct ldb_message **msgs;
249 struct ldb_message **remote_msgs = NULL;
250 unsigned int i;
251 int ret;
252 uint32_t acb;
253 bool add = false;
254 const char *attrs[] = { NULL };
255 /* we may change this to a global search, then fill in only the things not in ldap later */
256 const char *remote_attrs[] = { "userPrincipalName", "servicePrincipalName",
257 "msDS-KeyVersionNumber", "objectGUID", NULL};
259 user_sid = dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid);
260 if (!user_sid) {
261 return NT_STATUS_NO_MEMORY;
264 msg = ldb_msg_new(mem_ctx);
265 if (msg == NULL) {
266 return NT_STATUS_NO_MEMORY;
269 msg->dn = NULL;
270 /* search for the user, by rid */
271 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
272 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
273 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
275 if (ret == -1) {
276 *error_string = talloc_asprintf(mem_ctx, "LDB for user %s failed: %s",
277 dom_sid_string(mem_ctx, user_sid),
278 ldb_errstring(state->sam_ldb));
279 return NT_STATUS_INTERNAL_DB_CORRUPTION;
280 } else if (ret == 0) {
281 add = true;
282 } else if (ret > 1) {
283 *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s in local LDB",
284 dom_sid_string(mem_ctx, user_sid));
285 return NT_STATUS_INTERNAL_DB_CORRUPTION;
286 } else {
287 msg->dn = msgs[0]->dn;
288 talloc_steal(msg, msgs[0]->dn);
291 /* and do the same on the remote database */
292 if (state->remote_ldb) {
293 ret = gendb_search(state->remote_ldb, mem_ctx, state->base_dn[database],
294 &remote_msgs, remote_attrs, "(&(objectClass=user)(objectSid=%s))",
295 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
297 if (ret == -1) {
298 *error_string = talloc_asprintf(mem_ctx, "remote LDAP for user %s failed: %s",
299 dom_sid_string(mem_ctx, user_sid),
300 ldb_errstring(state->remote_ldb));
301 return NT_STATUS_INTERNAL_DB_CORRUPTION;
302 } else if (ret == 0) {
303 *error_string = talloc_asprintf(mem_ctx, "User exists in samsync but not in remote LDAP domain! (base: %s, SID: %s)",
304 ldb_dn_get_linearized(state->base_dn[database]),
305 dom_sid_string(mem_ctx, user_sid));
306 return NT_STATUS_NO_SUCH_USER;
307 } else if (ret > 1) {
308 *error_string = talloc_asprintf(mem_ctx, "More than one user in remote LDAP domain with SID: %s",
309 dom_sid_string(mem_ctx, user_sid));
310 return NT_STATUS_INTERNAL_DB_CORRUPTION;
312 /* Try to put things in the same location as the remote server */
313 } else if (add) {
314 msg->dn = talloc_steal(msg, remote_msgs[0]->dn);
318 cn_name = talloc_strdup(mem_ctx, user->account_name.string);
319 NT_STATUS_HAVE_NO_MEMORY(cn_name);
320 cn_name_len = strlen(cn_name);
322 #define ADD_OR_DEL(type, attrib, field) do { \
323 if (user->field) { \
324 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
325 attrib, user->field); \
326 } else if (!add) { \
327 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
328 attrib); \
330 } while (0);
332 ADD_OR_DEL(string, "samAccountName", account_name.string);
333 ADD_OR_DEL(string, "displayName", full_name.string);
335 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
336 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
337 return NT_STATUS_NO_MEMORY;
340 ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
341 ADD_OR_DEL(string, "homeDirectory", home_directory.string);
342 ADD_OR_DEL(string, "homeDrive", home_drive.string);
343 ADD_OR_DEL(string, "scriptPath", logon_script.string);
344 ADD_OR_DEL(string, "description", description.string);
345 ADD_OR_DEL(string, "userWorkstations", workstations.string);
347 ADD_OR_DEL(uint64, "lastLogon", last_logon);
348 ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
350 if (samdb_msg_add_logon_hours(state->sam_ldb, mem_ctx, msg, "logonHours", &user->logon_hours) != 0) {
351 return NT_STATUS_NO_MEMORY;
354 ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
355 ADD_OR_DEL(uint, "logonCount", logon_count);
357 ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
358 ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
360 if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg,
361 "userAccountControl", user->acct_flags) != 0) {
362 return NT_STATUS_NO_MEMORY;
365 if (user->lm_password_present) {
366 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
367 "dBCSPwd", &user->lmpassword);
368 } else if (!add) {
369 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
370 "dBCSPwd");
372 if (user->nt_password_present) {
373 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
374 "unicodePwd", &user->ntpassword);
375 } else if (!add) {
376 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
377 "unicodePwd");
380 ADD_OR_DEL(string, "comment", comment.string);
382 if (samdb_msg_add_parameters(state->sam_ldb, mem_ctx, msg, "userParameters", &user->parameters) != 0) {
383 return NT_STATUS_NO_MEMORY;
386 ADD_OR_DEL(uint, "countryCode", country_code);
387 ADD_OR_DEL(uint, "codePage", code_page);
389 ADD_OR_DEL(string, "profilePath", profile_path.string);
391 #undef ADD_OR_DEL
393 for (i=0; remote_attrs[i]; i++) {
394 struct ldb_message_element *el = ldb_msg_find_element(remote_msgs[0], remote_attrs[i]);
395 if (!el) {
396 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
397 remote_attrs[i]);
398 } else {
399 ldb_msg_add(msg, el, LDB_FLAG_MOD_REPLACE);
403 acb = user->acct_flags;
404 if (acb & (ACB_WSTRUST)) {
405 cn_name[cn_name_len - 1] = '\0';
406 container = "Computers";
407 obj_class = "computer";
409 } else if (acb & ACB_SVRTRUST) {
410 if (cn_name[cn_name_len - 1] != '$') {
411 return NT_STATUS_FOOBAR;
413 cn_name[cn_name_len - 1] = '\0';
414 container = "Domain Controllers";
415 obj_class = "computer";
416 } else {
417 container = "Users";
418 obj_class = "user";
420 if (add) {
421 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
422 "objectClass", obj_class);
423 if (!msg->dn) {
424 msg->dn = ldb_dn_copy(mem_ctx, state->base_dn[database]);
425 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container);
426 if (!msg->dn) {
427 return NT_STATUS_NO_MEMORY;
431 ret = ldb_add(state->sam_ldb, msg);
432 if (ret != LDB_SUCCESS) {
433 struct ldb_dn *first_try_dn = msg->dn;
434 /* Try again with the default DN */
435 if (!remote_msgs) {
436 *error_string = talloc_asprintf(mem_ctx, "Failed to create user record. Tried %s: %s",
437 ldb_dn_get_linearized(first_try_dn),
438 ldb_errstring(state->sam_ldb));
439 return NT_STATUS_INTERNAL_DB_CORRUPTION;
440 } else {
441 msg->dn = talloc_steal(msg, remote_msgs[0]->dn);
442 ret = ldb_add(state->sam_ldb, msg);
443 if (ret != LDB_SUCCESS) {
444 *error_string = talloc_asprintf(mem_ctx, "Failed to create user record. Tried both %s and %s: %s",
445 ldb_dn_get_linearized(first_try_dn),
446 ldb_dn_get_linearized(msg->dn),
447 ldb_errstring(state->sam_ldb));
448 return NT_STATUS_INTERNAL_DB_CORRUPTION;
452 } else {
453 ret = dsdb_replace(state->sam_ldb, msg, 0);
454 if (ret != LDB_SUCCESS) {
455 *error_string = talloc_asprintf(mem_ctx, "Failed to modify user record %s: %s",
456 ldb_dn_get_linearized(msg->dn),
457 ldb_errstring(state->sam_ldb));
458 return NT_STATUS_INTERNAL_DB_CORRUPTION;
462 return NT_STATUS_OK;
465 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
466 struct samsync_ldb_state *state,
467 enum netr_SamDatabaseID database,
468 struct netr_DELTA_ENUM *delta,
469 char **error_string)
471 uint32_t rid = delta->delta_id_union.rid;
472 struct ldb_message **msgs;
473 int ret;
474 const char *attrs[] = { NULL };
476 /* search for the user, by rid */
477 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
478 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
479 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
481 if (ret == -1) {
482 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
483 return NT_STATUS_INTERNAL_DB_CORRUPTION;
484 } else if (ret == 0) {
485 return NT_STATUS_NO_SUCH_USER;
486 } else if (ret > 1) {
487 *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s",
488 dom_sid_string(mem_ctx,
489 dom_sid_add_rid(mem_ctx,
490 state->dom_sid[database],
491 rid)));
492 return NT_STATUS_INTERNAL_DB_CORRUPTION;
495 ret = ldb_delete(state->sam_ldb, msgs[0]->dn);
496 if (ret != LDB_SUCCESS) {
497 *error_string = talloc_asprintf(mem_ctx, "Failed to delete user record %s: %s",
498 ldb_dn_get_linearized(msgs[0]->dn),
499 ldb_errstring(state->sam_ldb));
500 return NT_STATUS_INTERNAL_DB_CORRUPTION;
503 return NT_STATUS_OK;
506 static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
507 struct samsync_ldb_state *state,
508 enum netr_SamDatabaseID database,
509 struct netr_DELTA_ENUM *delta,
510 char **error_string)
512 uint32_t rid = delta->delta_id_union.rid;
513 struct netr_DELTA_GROUP *group = delta->delta_union.group;
514 const char *container, *obj_class;
515 const char *cn_name;
517 struct ldb_message *msg;
518 struct ldb_message **msgs;
519 int ret;
520 bool add = false;
521 const char *attrs[] = { NULL };
523 msg = ldb_msg_new(mem_ctx);
524 if (msg == NULL) {
525 return NT_STATUS_NO_MEMORY;
528 /* search for the group, by rid */
529 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
530 "(&(objectClass=group)(objectSid=%s))",
531 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
533 if (ret == -1) {
534 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
535 return NT_STATUS_INTERNAL_DB_CORRUPTION;
536 } else if (ret == 0) {
537 add = true;
538 } else if (ret > 1) {
539 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
540 dom_sid_string(mem_ctx,
541 dom_sid_add_rid(mem_ctx,
542 state->dom_sid[database],
543 rid)));
544 return NT_STATUS_INTERNAL_DB_CORRUPTION;
545 } else {
546 msg->dn = talloc_steal(msg, msgs[0]->dn);
549 cn_name = group->group_name.string;
551 #define ADD_OR_DEL(type, attrib, field) do { \
552 if (group->field) { \
553 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
554 attrib, group->field); \
555 } else if (!add) { \
556 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
557 attrib); \
559 } while (0);
561 ADD_OR_DEL(string, "samAccountName", group_name.string);
563 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
564 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
565 return NT_STATUS_NO_MEMORY;
568 ADD_OR_DEL(string, "description", description.string);
570 #undef ADD_OR_DEL
572 container = "Users";
573 obj_class = "group";
575 if (add) {
576 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
577 "objectClass", obj_class);
578 msg->dn = ldb_dn_copy(mem_ctx, state->base_dn[database]);
579 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container);
580 if (!msg->dn) {
581 return NT_STATUS_NO_MEMORY;
584 ret = ldb_add(state->sam_ldb, msg);
585 if (ret != LDB_SUCCESS) {
586 *error_string = talloc_asprintf(mem_ctx, "Failed to create group record %s: %s",
587 ldb_dn_get_linearized(msg->dn),
588 ldb_errstring(state->sam_ldb));
589 return NT_STATUS_INTERNAL_DB_CORRUPTION;
591 } else {
592 ret = dsdb_replace(state->sam_ldb, msg, 0);
593 if (ret != LDB_SUCCESS) {
594 *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
595 ldb_dn_get_linearized(msg->dn),
596 ldb_errstring(state->sam_ldb));
597 return NT_STATUS_INTERNAL_DB_CORRUPTION;
601 return NT_STATUS_OK;
604 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
605 struct samsync_ldb_state *state,
606 enum netr_SamDatabaseID database,
607 struct netr_DELTA_ENUM *delta,
608 char **error_string)
610 uint32_t rid = delta->delta_id_union.rid;
611 struct ldb_message **msgs;
612 int ret;
613 const char *attrs[] = { NULL };
615 /* search for the group, by rid */
616 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
617 "(&(objectClass=group)(objectSid=%s))",
618 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
620 if (ret == -1) {
621 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
622 return NT_STATUS_INTERNAL_DB_CORRUPTION;
623 } else if (ret == 0) {
624 return NT_STATUS_NO_SUCH_GROUP;
625 } else if (ret > 1) {
626 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
627 dom_sid_string(mem_ctx,
628 dom_sid_add_rid(mem_ctx,
629 state->dom_sid[database],
630 rid)));
631 return NT_STATUS_INTERNAL_DB_CORRUPTION;
634 ret = ldb_delete(state->sam_ldb, msgs[0]->dn);
635 if (ret != LDB_SUCCESS) {
636 *error_string = talloc_asprintf(mem_ctx, "Failed to delete group record %s: %s",
637 ldb_dn_get_linearized(msgs[0]->dn),
638 ldb_errstring(state->sam_ldb));
639 return NT_STATUS_INTERNAL_DB_CORRUPTION;
642 return NT_STATUS_OK;
645 static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
646 struct samsync_ldb_state *state,
647 enum netr_SamDatabaseID database,
648 struct netr_DELTA_ENUM *delta,
649 char **error_string)
651 uint32_t rid = delta->delta_id_union.rid;
652 struct netr_DELTA_GROUP_MEMBER *group_member = delta->delta_union.group_member;
653 struct ldb_message *msg;
654 struct ldb_message **msgs;
655 int ret;
656 const char *attrs[] = { NULL };
657 const char *str_dn;
658 uint32_t i;
660 msg = ldb_msg_new(mem_ctx);
661 if (msg == NULL) {
662 return NT_STATUS_NO_MEMORY;
665 /* search for the group, by rid */
666 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
667 "(&(objectClass=group)(objectSid=%s))",
668 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
670 if (ret == -1) {
671 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
672 return NT_STATUS_INTERNAL_DB_CORRUPTION;
673 } else if (ret == 0) {
674 return NT_STATUS_NO_SUCH_GROUP;
675 } else if (ret > 1) {
676 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
677 dom_sid_string(mem_ctx,
678 dom_sid_add_rid(mem_ctx,
679 state->dom_sid[database],
680 rid)));
681 return NT_STATUS_INTERNAL_DB_CORRUPTION;
682 } else {
683 msg->dn = talloc_steal(msg, msgs[0]->dn);
686 talloc_free(msgs);
688 for (i=0; i<group_member->num_rids; i++) {
689 /* search for the group, by rid */
690 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
691 "(&(objectClass=user)(objectSid=%s))",
692 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], group_member->rids[i])));
694 if (ret == -1) {
695 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
696 return NT_STATUS_INTERNAL_DB_CORRUPTION;
697 } else if (ret == 0) {
698 return NT_STATUS_NO_SUCH_USER;
699 } else if (ret > 1) {
700 return NT_STATUS_INTERNAL_DB_CORRUPTION;
701 } else {
702 str_dn = ldb_dn_alloc_linearized(msg, msgs[0]->dn);
703 NT_STATUS_HAVE_NO_MEMORY(str_dn);
704 ret = ldb_msg_add_string(msg, "member", str_dn);
705 if (ret != LDB_SUCCESS) return NT_STATUS_NO_MEMORY;
708 talloc_free(msgs);
711 ret = dsdb_replace(state->sam_ldb, msg, 0);
712 if (ret != LDB_SUCCESS) {
713 *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
714 ldb_dn_get_linearized(msg->dn),
715 ldb_errstring(state->sam_ldb));
716 return NT_STATUS_INTERNAL_DB_CORRUPTION;
719 return NT_STATUS_OK;
722 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
723 struct samsync_ldb_state *state,
724 enum netr_SamDatabaseID database,
725 struct netr_DELTA_ENUM *delta,
726 char **error_string)
728 uint32_t rid = delta->delta_id_union.rid;
729 struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
730 const char *container, *obj_class;
731 const char *cn_name;
733 struct ldb_message *msg;
734 struct ldb_message **msgs;
735 int ret;
736 bool add = false;
737 const char *attrs[] = { NULL };
739 msg = ldb_msg_new(mem_ctx);
740 if (msg == NULL) {
741 return NT_STATUS_NO_MEMORY;
744 /* search for the alias, by rid */
745 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
746 "(&(objectClass=group)(objectSid=%s))",
747 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
749 if (ret == -1) {
750 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
751 return NT_STATUS_INTERNAL_DB_CORRUPTION;
752 } else if (ret == 0) {
753 add = true;
754 } else if (ret > 1) {
755 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
756 dom_sid_string(mem_ctx,
757 dom_sid_add_rid(mem_ctx,
758 state->dom_sid[database],
759 rid)));
760 return NT_STATUS_INTERNAL_DB_CORRUPTION;
761 } else {
762 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
765 cn_name = alias->alias_name.string;
767 #define ADD_OR_DEL(type, attrib, field) do { \
768 if (alias->field) { \
769 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
770 attrib, alias->field); \
771 } else if (!add) { \
772 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
773 attrib); \
775 } while (0);
777 ADD_OR_DEL(string, "samAccountName", alias_name.string);
779 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
780 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
781 return NT_STATUS_NO_MEMORY;
784 ADD_OR_DEL(string, "description", description.string);
786 #undef ADD_OR_DEL
788 samdb_msg_add_uint(state->sam_ldb, mem_ctx, msg, "groupType", 0x80000004);
790 container = "Users";
791 obj_class = "group";
793 if (add) {
794 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
795 "objectClass", obj_class);
796 msg->dn = ldb_dn_copy(mem_ctx, state->base_dn[database]);
797 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container);
798 if (!msg->dn) {
799 return NT_STATUS_NO_MEMORY;
802 ret = ldb_add(state->sam_ldb, msg);
803 if (ret != LDB_SUCCESS) {
804 *error_string = talloc_asprintf(mem_ctx, "Failed to create alias record %s: %s",
805 ldb_dn_get_linearized(msg->dn),
806 ldb_errstring(state->sam_ldb));
807 return NT_STATUS_INTERNAL_DB_CORRUPTION;
809 } else {
810 ret = dsdb_replace(state->sam_ldb, msg, 0);
811 if (ret != LDB_SUCCESS) {
812 *error_string = talloc_asprintf(mem_ctx, "Failed to modify alias record %s: %s",
813 ldb_dn_get_linearized(msg->dn),
814 ldb_errstring(state->sam_ldb));
815 return NT_STATUS_INTERNAL_DB_CORRUPTION;
819 return NT_STATUS_OK;
822 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
823 struct samsync_ldb_state *state,
824 enum netr_SamDatabaseID database,
825 struct netr_DELTA_ENUM *delta,
826 char **error_string)
828 uint32_t rid = delta->delta_id_union.rid;
829 struct ldb_message **msgs;
830 int ret;
831 const char *attrs[] = { NULL };
833 /* search for the alias, by rid */
834 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
835 "(&(objectClass=group)(objectSid=%s))",
836 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
838 if (ret == -1) {
839 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
840 return NT_STATUS_INTERNAL_DB_CORRUPTION;
841 } else if (ret == 0) {
842 return NT_STATUS_NO_SUCH_ALIAS;
843 } else if (ret > 1) {
844 return NT_STATUS_INTERNAL_DB_CORRUPTION;
847 ret = ldb_delete(state->sam_ldb, msgs[0]->dn);
848 if (ret != LDB_SUCCESS) {
849 *error_string = talloc_asprintf(mem_ctx, "Failed to delete alias record %s: %s",
850 ldb_dn_get_linearized(msgs[0]->dn),
851 ldb_errstring(state->sam_ldb));
852 return NT_STATUS_INTERNAL_DB_CORRUPTION;
855 return NT_STATUS_OK;
858 static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
859 struct samsync_ldb_state *state,
860 enum netr_SamDatabaseID database,
861 struct netr_DELTA_ENUM *delta,
862 char **error_string)
864 uint32_t rid = delta->delta_id_union.rid;
865 struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
866 struct ldb_message *msg;
867 struct ldb_message **msgs;
868 int ret;
869 const char *attrs[] = { NULL };
870 uint32_t i;
872 msg = ldb_msg_new(mem_ctx);
873 if (msg == NULL) {
874 return NT_STATUS_NO_MEMORY;
877 /* search for the alias, by rid */
878 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
879 "(&(objectClass=group)(objectSid=%s))",
880 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
882 if (ret == -1) {
883 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
884 return NT_STATUS_INTERNAL_DB_CORRUPTION;
885 } else if (ret == 0) {
886 return NT_STATUS_NO_SUCH_GROUP;
887 } else if (ret > 1) {
888 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
889 dom_sid_string(mem_ctx,
890 dom_sid_add_rid(mem_ctx,
891 state->dom_sid[database],
892 rid)));
893 return NT_STATUS_INTERNAL_DB_CORRUPTION;
894 } else {
895 msg->dn = talloc_steal(msg, msgs[0]->dn);
898 talloc_free(msgs);
900 for (i=0; i<alias_member->sids.num_sids; i++) {
901 struct ldb_dn *alias_member_dn;
902 const char *str_dn;
903 /* search for members, in the top basedn (normal users are builtin aliases) */
904 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
905 "(objectSid=%s)",
906 ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid));
908 if (ret == -1) {
909 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
910 return NT_STATUS_INTERNAL_DB_CORRUPTION;
911 } else if (ret == 0) {
912 NTSTATUS nt_status;
913 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
914 alias_member->sids.sids[i].sid,
915 &alias_member_dn,
916 error_string);
917 if (!NT_STATUS_IS_OK(nt_status)) {
918 return nt_status;
920 } else if (ret > 1) {
921 return NT_STATUS_INTERNAL_DB_CORRUPTION;
922 } else {
923 alias_member_dn = msgs[0]->dn;
925 str_dn = ldb_dn_alloc_linearized(msg, alias_member_dn);
926 NT_STATUS_HAVE_NO_MEMORY(str_dn);
927 ret = ldb_msg_add_string(msg, "member", str_dn);
928 if (ret != LDB_SUCCESS) return NT_STATUS_NO_MEMORY;
930 talloc_free(msgs);
933 ret = dsdb_replace(state->sam_ldb, msg, 0);
934 if (ret != LDB_SUCCESS) {
935 *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
936 ldb_dn_get_linearized(msg->dn),
937 ldb_errstring(state->sam_ldb));
938 return NT_STATUS_INTERNAL_DB_CORRUPTION;
941 return NT_STATUS_OK;
944 static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
945 struct samsync_ldb_state *state,
946 enum netr_SamDatabaseID database,
947 struct netr_DELTA_ENUM *delta,
948 char **error_string)
950 struct dom_sid *sid = delta->delta_id_union.sid;
951 struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
953 struct ldb_message *msg;
954 int ret;
955 uint32_t i;
956 char *dnstr, *sidstr;
958 msg = ldb_msg_new(mem_ctx);
959 if (msg == NULL) {
960 return NT_STATUS_NO_MEMORY;
963 sidstr = dom_sid_string(msg, sid);
964 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sidstr, msg);
966 dnstr = talloc_asprintf(msg, "sid=%s", sidstr);
967 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dnstr, msg);
969 msg->dn = ldb_dn_new(msg, state->pdb, dnstr);
970 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(msg->dn, msg);
972 for (i=0; i< account->privilege_entries; i++) {
973 samdb_msg_add_string(state->pdb, mem_ctx, msg, "privilege",
974 account->privilege_name[i].string);
977 ret = dsdb_replace(state->pdb, msg, 0);
978 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
979 if (samdb_msg_add_dom_sid(state->pdb, msg, msg, "objectSid", sid) != LDB_SUCCESS) {
980 talloc_free(msg);
981 return NT_STATUS_NO_MEMORY;
983 samdb_msg_add_string(state->pdb, msg, msg, "comment", "added via samsync");
984 ret = ldb_add(state->pdb, msg);
987 if (ret != LDB_SUCCESS) {
988 *error_string = talloc_asprintf(mem_ctx, "Failed to modify privilege record %s",
989 ldb_dn_get_linearized(msg->dn));
990 return NT_STATUS_INTERNAL_DB_CORRUPTION;
993 return NT_STATUS_OK;
996 static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
997 struct samsync_ldb_state *state,
998 enum netr_SamDatabaseID database,
999 struct netr_DELTA_ENUM *delta,
1000 char **error_string)
1002 struct dom_sid *sid = delta->delta_id_union.sid;
1004 struct ldb_message *msg;
1005 struct ldb_message **msgs;
1006 int ret;
1007 const char *attrs[] = { NULL };
1009 msg = ldb_msg_new(mem_ctx);
1010 if (msg == NULL) {
1011 return NT_STATUS_NO_MEMORY;
1014 /* search for the account, by sid, in the top basedn */
1015 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
1016 "(objectSid=%s)",
1017 ldap_encode_ndr_dom_sid(mem_ctx, sid));
1019 if (ret == -1) {
1020 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
1021 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1022 } else if (ret == 0) {
1023 return NT_STATUS_NO_SUCH_USER;
1024 } else if (ret > 1) {
1025 *error_string = talloc_asprintf(mem_ctx, "More than one account with SID: %s",
1026 dom_sid_string(mem_ctx, sid));
1027 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1028 } else {
1029 msg->dn = talloc_steal(msg, msgs[0]->dn);
1032 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
1033 "privilege");
1035 ret = dsdb_replace(state->sam_ldb, msg, 0);
1036 if (ret != LDB_SUCCESS) {
1037 *error_string = talloc_asprintf(mem_ctx, "Failed to modify privilege record %s",
1038 ldb_dn_get_linearized(msg->dn));
1039 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1042 return NT_STATUS_OK;
1045 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,
1046 void *private_data,
1047 enum netr_SamDatabaseID database,
1048 struct netr_DELTA_ENUM *delta,
1049 char **error_string)
1051 NTSTATUS nt_status = NT_STATUS_OK;
1052 struct samsync_ldb_state *state = talloc_get_type(private_data, struct samsync_ldb_state);
1054 *error_string = NULL;
1055 switch (delta->delta_type) {
1056 case NETR_DELTA_DOMAIN:
1058 nt_status = samsync_ldb_handle_domain(mem_ctx,
1059 state,
1060 database,
1061 delta,
1062 error_string);
1063 break;
1065 case NETR_DELTA_USER:
1067 nt_status = samsync_ldb_handle_user(mem_ctx,
1068 state,
1069 database,
1070 delta,
1071 error_string);
1072 break;
1074 case NETR_DELTA_DELETE_USER:
1076 nt_status = samsync_ldb_delete_user(mem_ctx,
1077 state,
1078 database,
1079 delta,
1080 error_string);
1081 break;
1083 case NETR_DELTA_GROUP:
1085 nt_status = samsync_ldb_handle_group(mem_ctx,
1086 state,
1087 database,
1088 delta,
1089 error_string);
1090 break;
1092 case NETR_DELTA_DELETE_GROUP:
1094 nt_status = samsync_ldb_delete_group(mem_ctx,
1095 state,
1096 database,
1097 delta,
1098 error_string);
1099 break;
1101 case NETR_DELTA_GROUP_MEMBER:
1103 nt_status = samsync_ldb_handle_group_member(mem_ctx,
1104 state,
1105 database,
1106 delta,
1107 error_string);
1108 break;
1110 case NETR_DELTA_ALIAS:
1112 nt_status = samsync_ldb_handle_alias(mem_ctx,
1113 state,
1114 database,
1115 delta,
1116 error_string);
1117 break;
1119 case NETR_DELTA_DELETE_ALIAS:
1121 nt_status = samsync_ldb_delete_alias(mem_ctx,
1122 state,
1123 database,
1124 delta,
1125 error_string);
1126 break;
1128 case NETR_DELTA_ALIAS_MEMBER:
1130 nt_status = samsync_ldb_handle_alias_member(mem_ctx,
1131 state,
1132 database,
1133 delta,
1134 error_string);
1135 break;
1137 case NETR_DELTA_ACCOUNT:
1139 nt_status = samsync_ldb_handle_account(mem_ctx,
1140 state,
1141 database,
1142 delta,
1143 error_string);
1144 break;
1146 case NETR_DELTA_DELETE_ACCOUNT:
1148 nt_status = samsync_ldb_delete_account(mem_ctx,
1149 state,
1150 database,
1151 delta,
1152 error_string);
1153 break;
1155 default:
1156 /* Can't dump them all right now */
1157 break;
1159 if (!NT_STATUS_IS_OK(nt_status) && !*error_string) {
1160 *error_string = talloc_asprintf(mem_ctx, "Failed to handle samsync delta: %s", nt_errstr(nt_status));
1162 return nt_status;
1165 static NTSTATUS libnet_samsync_ldb_init(TALLOC_CTX *mem_ctx,
1166 void *private_data,
1167 struct libnet_SamSync_state *samsync_state,
1168 char **error_string)
1170 struct samsync_ldb_state *state = talloc_get_type(private_data, struct samsync_ldb_state);
1171 const char *server = dcerpc_server_name(samsync_state->netlogon_pipe);
1172 char *ldap_url;
1174 state->samsync_state = samsync_state;
1176 ZERO_STRUCT(state->dom_sid);
1177 if (state->samsync_state->domain_sid) {
1178 state->dom_sid[SAM_DATABASE_DOMAIN] = dom_sid_dup(state, state->samsync_state->domain_sid);
1181 state->dom_sid[SAM_DATABASE_BUILTIN] = dom_sid_parse_talloc(state, SID_BUILTIN);
1183 if (state->samsync_state->realm) {
1184 if (!server || !*server) {
1185 /* huh? how do we not have a server name? */
1186 *error_string = talloc_strdup(mem_ctx, "No DCE/RPC server name available. How did we connect?");
1187 return NT_STATUS_INVALID_PARAMETER;
1189 ldap_url = talloc_asprintf(state, "ldap://%s", server);
1191 state->remote_ldb = ldb_wrap_connect(mem_ctx,
1192 state->samsync_state->machine_net_ctx->event_ctx,
1193 state->samsync_state->machine_net_ctx->lp_ctx,
1194 ldap_url,
1195 NULL, state->samsync_state->machine_net_ctx->cred,
1197 if (!state->remote_ldb) {
1198 *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);
1199 return NT_STATUS_NO_LOGON_SERVERS;
1201 } else {
1202 state->remote_ldb = NULL;
1204 return NT_STATUS_OK;
1207 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1209 NTSTATUS nt_status;
1210 struct libnet_SamSync r2;
1211 struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
1213 if (!state) {
1214 return NT_STATUS_NO_MEMORY;
1217 state->secrets = NULL;
1218 state->trusted_domains = NULL;
1220 state->sam_ldb = samdb_connect(mem_ctx,
1221 ctx->event_ctx,
1222 ctx->lp_ctx,
1223 r->in.session_info,
1225 if (!state->sam_ldb) {
1226 return NT_STATUS_INTERNAL_DB_ERROR;
1229 state->pdb = privilege_connect(mem_ctx,
1230 ctx->event_ctx,
1231 ctx->lp_ctx);
1232 if (!state->pdb) {
1233 return NT_STATUS_INTERNAL_DB_ERROR;
1236 r2.out.error_string = NULL;
1237 r2.in.binding_string = r->in.binding_string;
1238 r2.in.init_fn = libnet_samsync_ldb_init;
1239 r2.in.delta_fn = libnet_samsync_ldb_fn;
1240 r2.in.fn_ctx = state;
1241 r2.in.machine_account = NULL; /* TODO: Create a machine account, fill this in, and the delete it */
1242 nt_status = libnet_SamSync_netlogon(ctx, state, &r2);
1243 r->out.error_string = r2.out.error_string;
1244 talloc_steal(mem_ctx, r->out.error_string);
1246 if (!NT_STATUS_IS_OK(nt_status)) {
1247 talloc_free(state);
1248 return nt_status;
1250 talloc_free(state);
1251 return nt_status;