s3-selftest: Remove some unnecessary comma
[Samba/gebeck_regimport.git] / source4 / libnet / libnet_samsync_ldb.c
blob20f004657bef8c6db4fd13b3aeca3989e29c433a
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 samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx,
165 msg, "objectSid", state->dom_sid[database]);
166 } else {
167 /* Well, we will have to use the one from the database */
168 state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state,
169 state->base_dn[database],
170 "objectSid", NULL);
173 if (state->samsync_state->domain_guid) {
174 struct ldb_val v;
175 NTSTATUS status;
176 status = GUID_to_ndr_blob(state->samsync_state->domain_guid, msg, &v);
177 if (!NT_STATUS_IS_OK(status)) {
178 *error_string = talloc_asprintf(mem_ctx, "ndr_push of domain GUID failed!");
179 return status;
182 ldb_msg_add_value(msg, "objectGUID", &v, NULL);
184 } else if (database == SAM_DATABASE_BUILTIN) {
185 /* work out the builtin_dn - useful for so many calls its worth
186 fetching here */
187 const char *dnstring = samdb_search_string(state->sam_ldb, mem_ctx, NULL,
188 "distinguishedName", "objectClass=builtinDomain");
189 state->base_dn[database] = ldb_dn_new(state, state->sam_ldb, dnstring);
190 if ( ! ldb_dn_validate(state->base_dn[database])) {
191 return NT_STATUS_INTERNAL_ERROR;
193 } else {
194 /* PRIVs DB */
195 return NT_STATUS_INVALID_PARAMETER;
198 msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
199 if (!msg->dn) {
200 return NT_STATUS_NO_MEMORY;
203 ldb_msg_add_string(msg, "oEMInformation",
204 domain->oem_information.string);
206 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
207 msg, "forceLogoff", domain->force_logoff_time);
209 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
210 msg, "minPwdLen", domain->min_password_length);
212 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
213 msg, "maxPwdAge", domain->max_password_age);
215 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
216 msg, "minPwdAge", domain->min_password_age);
218 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
219 msg, "pwdHistoryLength", domain->password_history_length);
221 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
222 msg, "modifiedCount",
223 domain->sequence_num);
225 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
226 msg, "creationTime", domain->domain_create_time);
228 /* TODO: Account lockout, password properties */
230 ret = dsdb_replace(state->sam_ldb, msg, 0);
231 if (ret != LDB_SUCCESS) {
232 *error_string = talloc_asprintf(mem_ctx,
233 "Failed to modify domain record %s: %s",
234 ldb_dn_get_linearized(msg->dn),
235 ldb_errstring(state->sam_ldb));
236 return NT_STATUS_INTERNAL_DB_CORRUPTION;
238 return NT_STATUS_OK;
241 static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
242 struct samsync_ldb_state *state,
243 enum netr_SamDatabaseID database,
244 struct netr_DELTA_ENUM *delta,
245 char **error_string)
247 uint32_t rid = delta->delta_id_union.rid;
248 struct netr_DELTA_USER *user = delta->delta_union.user;
249 const char *container, *obj_class;
250 char *cn_name;
251 int cn_name_len;
252 const struct dom_sid *user_sid;
253 struct ldb_message *msg;
254 struct ldb_message **msgs;
255 struct ldb_message **remote_msgs = NULL;
256 unsigned int i;
257 int ret;
258 uint32_t acb;
259 bool add = false;
260 const char *attrs[] = { NULL };
261 /* we may change this to a global search, then fill in only the things not in ldap later */
262 const char *remote_attrs[] = { "userPrincipalName", "servicePrincipalName",
263 "msDS-KeyVersionNumber", "objectGUID", NULL};
265 user_sid = dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid);
266 if (!user_sid) {
267 return NT_STATUS_NO_MEMORY;
270 msg = ldb_msg_new(mem_ctx);
271 if (msg == NULL) {
272 return NT_STATUS_NO_MEMORY;
275 msg->dn = NULL;
276 /* search for the user, by rid */
277 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
278 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
279 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
281 if (ret == -1) {
282 *error_string = talloc_asprintf(mem_ctx, "LDB for user %s failed: %s",
283 dom_sid_string(mem_ctx, user_sid),
284 ldb_errstring(state->sam_ldb));
285 return NT_STATUS_INTERNAL_DB_CORRUPTION;
286 } else if (ret == 0) {
287 add = true;
288 } else if (ret > 1) {
289 *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s in local LDB",
290 dom_sid_string(mem_ctx, user_sid));
291 return NT_STATUS_INTERNAL_DB_CORRUPTION;
292 } else {
293 msg->dn = msgs[0]->dn;
294 talloc_steal(msg, msgs[0]->dn);
297 /* and do the same on the remote database */
298 if (state->remote_ldb) {
299 ret = gendb_search(state->remote_ldb, mem_ctx, state->base_dn[database],
300 &remote_msgs, remote_attrs, "(&(objectClass=user)(objectSid=%s))",
301 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
303 if (ret == -1) {
304 *error_string = talloc_asprintf(mem_ctx, "remote LDAP for user %s failed: %s",
305 dom_sid_string(mem_ctx, user_sid),
306 ldb_errstring(state->remote_ldb));
307 return NT_STATUS_INTERNAL_DB_CORRUPTION;
308 } else if (ret == 0) {
309 *error_string = talloc_asprintf(mem_ctx, "User exists in samsync but not in remote LDAP domain! (base: %s, SID: %s)",
310 ldb_dn_get_linearized(state->base_dn[database]),
311 dom_sid_string(mem_ctx, user_sid));
312 return NT_STATUS_NO_SUCH_USER;
313 } else if (ret > 1) {
314 *error_string = talloc_asprintf(mem_ctx, "More than one user in remote LDAP domain with SID: %s",
315 dom_sid_string(mem_ctx, user_sid));
316 return NT_STATUS_INTERNAL_DB_CORRUPTION;
318 /* Try to put things in the same location as the remote server */
319 } else if (add) {
320 msg->dn = talloc_steal(msg, remote_msgs[0]->dn);
324 cn_name = talloc_strdup(mem_ctx, user->account_name.string);
325 NT_STATUS_HAVE_NO_MEMORY(cn_name);
326 cn_name_len = strlen(cn_name);
328 #define ADD_OR_DEL(type, attrib, field) do { \
329 if (user->field) { \
330 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
331 attrib, user->field); \
332 } else if (!add) { \
333 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
334 attrib); \
336 } while (0);
338 ADD_OR_DEL(string, "samAccountName", account_name.string);
339 ADD_OR_DEL(string, "displayName", full_name.string);
341 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
342 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
343 return NT_STATUS_NO_MEMORY;
346 ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
347 ADD_OR_DEL(string, "homeDirectory", home_directory.string);
348 ADD_OR_DEL(string, "homeDrive", home_drive.string);
349 ADD_OR_DEL(string, "scriptPath", logon_script.string);
350 ADD_OR_DEL(string, "description", description.string);
351 ADD_OR_DEL(string, "userWorkstations", workstations.string);
353 ADD_OR_DEL(uint64, "lastLogon", last_logon);
354 ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
356 if (samdb_msg_add_logon_hours(state->sam_ldb, mem_ctx, msg, "logonHours", &user->logon_hours) != 0) {
357 return NT_STATUS_NO_MEMORY;
360 ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
361 ADD_OR_DEL(uint, "logonCount", logon_count);
363 ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
364 ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
366 if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg,
367 "userAccountControl", user->acct_flags) != 0) {
368 return NT_STATUS_NO_MEMORY;
371 if (user->lm_password_present) {
372 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
373 "dBCSPwd", &user->lmpassword);
374 } else if (!add) {
375 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
376 "dBCSPwd");
378 if (user->nt_password_present) {
379 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
380 "unicodePwd", &user->ntpassword);
381 } else if (!add) {
382 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
383 "unicodePwd");
386 ADD_OR_DEL(string, "comment", comment.string);
388 if (samdb_msg_add_parameters(state->sam_ldb, mem_ctx, msg, "userParameters", &user->parameters) != 0) {
389 return NT_STATUS_NO_MEMORY;
392 ADD_OR_DEL(uint, "countryCode", country_code);
393 ADD_OR_DEL(uint, "codePage", code_page);
395 ADD_OR_DEL(string, "profilePath", profile_path.string);
397 #undef ADD_OR_DEL
399 for (i=0; remote_attrs[i]; i++) {
400 struct ldb_message_element *el = ldb_msg_find_element(remote_msgs[0], remote_attrs[i]);
401 if (!el) {
402 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
403 remote_attrs[i]);
404 } else {
405 ldb_msg_add(msg, el, LDB_FLAG_MOD_REPLACE);
409 acb = user->acct_flags;
410 if (acb & (ACB_WSTRUST)) {
411 cn_name[cn_name_len - 1] = '\0';
412 container = "Computers";
413 obj_class = "computer";
415 } else if (acb & ACB_SVRTRUST) {
416 if (cn_name[cn_name_len - 1] != '$') {
417 return NT_STATUS_FOOBAR;
419 cn_name[cn_name_len - 1] = '\0';
420 container = "Domain Controllers";
421 obj_class = "computer";
422 } else {
423 container = "Users";
424 obj_class = "user";
426 if (add) {
427 ldb_msg_add_string(msg, "objectClass", obj_class);
428 if (!msg->dn) {
429 msg->dn = ldb_dn_copy(mem_ctx, state->base_dn[database]);
430 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container);
431 if (!msg->dn) {
432 return NT_STATUS_NO_MEMORY;
436 ret = ldb_add(state->sam_ldb, msg);
437 if (ret != LDB_SUCCESS) {
438 struct ldb_dn *first_try_dn = msg->dn;
439 /* Try again with the default DN */
440 if (!remote_msgs) {
441 *error_string = talloc_asprintf(mem_ctx, "Failed to create user record. Tried %s: %s",
442 ldb_dn_get_linearized(first_try_dn),
443 ldb_errstring(state->sam_ldb));
444 return NT_STATUS_INTERNAL_DB_CORRUPTION;
445 } else {
446 msg->dn = talloc_steal(msg, remote_msgs[0]->dn);
447 ret = ldb_add(state->sam_ldb, msg);
448 if (ret != LDB_SUCCESS) {
449 *error_string = talloc_asprintf(mem_ctx, "Failed to create user record. Tried both %s and %s: %s",
450 ldb_dn_get_linearized(first_try_dn),
451 ldb_dn_get_linearized(msg->dn),
452 ldb_errstring(state->sam_ldb));
453 return NT_STATUS_INTERNAL_DB_CORRUPTION;
457 } else {
458 ret = dsdb_replace(state->sam_ldb, msg, 0);
459 if (ret != LDB_SUCCESS) {
460 *error_string = talloc_asprintf(mem_ctx, "Failed to modify user record %s: %s",
461 ldb_dn_get_linearized(msg->dn),
462 ldb_errstring(state->sam_ldb));
463 return NT_STATUS_INTERNAL_DB_CORRUPTION;
467 return NT_STATUS_OK;
470 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
471 struct samsync_ldb_state *state,
472 enum netr_SamDatabaseID database,
473 struct netr_DELTA_ENUM *delta,
474 char **error_string)
476 uint32_t rid = delta->delta_id_union.rid;
477 struct ldb_message **msgs;
478 int ret;
479 const char *attrs[] = { NULL };
481 /* search for the user, by rid */
482 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
483 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
484 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
486 if (ret == -1) {
487 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
488 return NT_STATUS_INTERNAL_DB_CORRUPTION;
489 } else if (ret == 0) {
490 return NT_STATUS_NO_SUCH_USER;
491 } else if (ret > 1) {
492 *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s",
493 dom_sid_string(mem_ctx,
494 dom_sid_add_rid(mem_ctx,
495 state->dom_sid[database],
496 rid)));
497 return NT_STATUS_INTERNAL_DB_CORRUPTION;
500 ret = ldb_delete(state->sam_ldb, msgs[0]->dn);
501 if (ret != LDB_SUCCESS) {
502 *error_string = talloc_asprintf(mem_ctx, "Failed to delete user record %s: %s",
503 ldb_dn_get_linearized(msgs[0]->dn),
504 ldb_errstring(state->sam_ldb));
505 return NT_STATUS_INTERNAL_DB_CORRUPTION;
508 return NT_STATUS_OK;
511 static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
512 struct samsync_ldb_state *state,
513 enum netr_SamDatabaseID database,
514 struct netr_DELTA_ENUM *delta,
515 char **error_string)
517 uint32_t rid = delta->delta_id_union.rid;
518 struct netr_DELTA_GROUP *group = delta->delta_union.group;
519 const char *container, *obj_class;
520 const char *cn_name;
522 struct ldb_message *msg;
523 struct ldb_message **msgs;
524 int ret;
525 bool add = false;
526 const char *attrs[] = { NULL };
528 msg = ldb_msg_new(mem_ctx);
529 if (msg == NULL) {
530 return NT_STATUS_NO_MEMORY;
533 /* search for the group, by rid */
534 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
535 "(&(objectClass=group)(objectSid=%s))",
536 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
538 if (ret == -1) {
539 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
540 return NT_STATUS_INTERNAL_DB_CORRUPTION;
541 } else if (ret == 0) {
542 add = true;
543 } else if (ret > 1) {
544 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
545 dom_sid_string(mem_ctx,
546 dom_sid_add_rid(mem_ctx,
547 state->dom_sid[database],
548 rid)));
549 return NT_STATUS_INTERNAL_DB_CORRUPTION;
550 } else {
551 msg->dn = talloc_steal(msg, msgs[0]->dn);
554 cn_name = group->group_name.string;
556 #define ADD_OR_DEL(type, attrib, field) do { \
557 if (group->field) { \
558 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
559 attrib, group->field); \
560 } else if (!add) { \
561 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
562 attrib); \
564 } while (0);
566 ADD_OR_DEL(string, "samAccountName", group_name.string);
568 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
569 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
570 return NT_STATUS_NO_MEMORY;
573 ADD_OR_DEL(string, "description", description.string);
575 #undef ADD_OR_DEL
577 container = "Users";
578 obj_class = "group";
580 if (add) {
581 ldb_msg_add_string(msg, "objectClass", obj_class);
582 msg->dn = ldb_dn_copy(mem_ctx, state->base_dn[database]);
583 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container);
584 if (!msg->dn) {
585 return NT_STATUS_NO_MEMORY;
588 ret = ldb_add(state->sam_ldb, msg);
589 if (ret != LDB_SUCCESS) {
590 *error_string = talloc_asprintf(mem_ctx, "Failed to create group record %s: %s",
591 ldb_dn_get_linearized(msg->dn),
592 ldb_errstring(state->sam_ldb));
593 return NT_STATUS_INTERNAL_DB_CORRUPTION;
595 } else {
596 ret = dsdb_replace(state->sam_ldb, msg, 0);
597 if (ret != LDB_SUCCESS) {
598 *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
599 ldb_dn_get_linearized(msg->dn),
600 ldb_errstring(state->sam_ldb));
601 return NT_STATUS_INTERNAL_DB_CORRUPTION;
605 return NT_STATUS_OK;
608 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
609 struct samsync_ldb_state *state,
610 enum netr_SamDatabaseID database,
611 struct netr_DELTA_ENUM *delta,
612 char **error_string)
614 uint32_t rid = delta->delta_id_union.rid;
615 struct ldb_message **msgs;
616 int ret;
617 const char *attrs[] = { NULL };
619 /* search for the group, by rid */
620 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
621 "(&(objectClass=group)(objectSid=%s))",
622 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
624 if (ret == -1) {
625 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
626 return NT_STATUS_INTERNAL_DB_CORRUPTION;
627 } else if (ret == 0) {
628 return NT_STATUS_NO_SUCH_GROUP;
629 } else if (ret > 1) {
630 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
631 dom_sid_string(mem_ctx,
632 dom_sid_add_rid(mem_ctx,
633 state->dom_sid[database],
634 rid)));
635 return NT_STATUS_INTERNAL_DB_CORRUPTION;
638 ret = ldb_delete(state->sam_ldb, msgs[0]->dn);
639 if (ret != LDB_SUCCESS) {
640 *error_string = talloc_asprintf(mem_ctx, "Failed to delete group record %s: %s",
641 ldb_dn_get_linearized(msgs[0]->dn),
642 ldb_errstring(state->sam_ldb));
643 return NT_STATUS_INTERNAL_DB_CORRUPTION;
646 return NT_STATUS_OK;
649 static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
650 struct samsync_ldb_state *state,
651 enum netr_SamDatabaseID database,
652 struct netr_DELTA_ENUM *delta,
653 char **error_string)
655 uint32_t rid = delta->delta_id_union.rid;
656 struct netr_DELTA_GROUP_MEMBER *group_member = delta->delta_union.group_member;
657 struct ldb_message *msg;
658 struct ldb_message **msgs;
659 int ret;
660 const char *attrs[] = { NULL };
661 const char *str_dn;
662 uint32_t i;
664 msg = ldb_msg_new(mem_ctx);
665 if (msg == NULL) {
666 return NT_STATUS_NO_MEMORY;
669 /* search for the group, by rid */
670 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
671 "(&(objectClass=group)(objectSid=%s))",
672 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
674 if (ret == -1) {
675 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
676 return NT_STATUS_INTERNAL_DB_CORRUPTION;
677 } else if (ret == 0) {
678 return NT_STATUS_NO_SUCH_GROUP;
679 } else if (ret > 1) {
680 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
681 dom_sid_string(mem_ctx,
682 dom_sid_add_rid(mem_ctx,
683 state->dom_sid[database],
684 rid)));
685 return NT_STATUS_INTERNAL_DB_CORRUPTION;
686 } else {
687 msg->dn = talloc_steal(msg, msgs[0]->dn);
690 talloc_free(msgs);
692 for (i=0; i<group_member->num_rids; i++) {
693 /* search for the group, by rid */
694 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
695 "(&(objectClass=user)(objectSid=%s))",
696 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], group_member->rids[i])));
698 if (ret == -1) {
699 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
700 return NT_STATUS_INTERNAL_DB_CORRUPTION;
701 } else if (ret == 0) {
702 return NT_STATUS_NO_SUCH_USER;
703 } else if (ret > 1) {
704 return NT_STATUS_INTERNAL_DB_CORRUPTION;
705 } else {
706 str_dn = ldb_dn_alloc_linearized(msg, msgs[0]->dn);
707 NT_STATUS_HAVE_NO_MEMORY(str_dn);
708 ret = ldb_msg_add_string(msg, "member", str_dn);
709 if (ret != LDB_SUCCESS) return NT_STATUS_NO_MEMORY;
712 talloc_free(msgs);
715 ret = dsdb_replace(state->sam_ldb, msg, 0);
716 if (ret != LDB_SUCCESS) {
717 *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
718 ldb_dn_get_linearized(msg->dn),
719 ldb_errstring(state->sam_ldb));
720 return NT_STATUS_INTERNAL_DB_CORRUPTION;
723 return NT_STATUS_OK;
726 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
727 struct samsync_ldb_state *state,
728 enum netr_SamDatabaseID database,
729 struct netr_DELTA_ENUM *delta,
730 char **error_string)
732 uint32_t rid = delta->delta_id_union.rid;
733 struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
734 const char *container, *obj_class;
735 const char *cn_name;
737 struct ldb_message *msg;
738 struct ldb_message **msgs;
739 int ret;
740 bool add = false;
741 const char *attrs[] = { NULL };
743 msg = ldb_msg_new(mem_ctx);
744 if (msg == NULL) {
745 return NT_STATUS_NO_MEMORY;
748 /* search for the alias, by rid */
749 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
750 "(&(objectClass=group)(objectSid=%s))",
751 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
753 if (ret == -1) {
754 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
755 return NT_STATUS_INTERNAL_DB_CORRUPTION;
756 } else if (ret == 0) {
757 add = true;
758 } else if (ret > 1) {
759 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
760 dom_sid_string(mem_ctx,
761 dom_sid_add_rid(mem_ctx,
762 state->dom_sid[database],
763 rid)));
764 return NT_STATUS_INTERNAL_DB_CORRUPTION;
765 } else {
766 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
769 cn_name = alias->alias_name.string;
771 #define ADD_OR_DEL(type, attrib, field) do { \
772 if (alias->field) { \
773 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
774 attrib, alias->field); \
775 } else if (!add) { \
776 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
777 attrib); \
779 } while (0);
781 ADD_OR_DEL(string, "samAccountName", alias_name.string);
783 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
784 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
785 return NT_STATUS_NO_MEMORY;
788 ADD_OR_DEL(string, "description", description.string);
790 #undef ADD_OR_DEL
792 samdb_msg_add_uint(state->sam_ldb, mem_ctx, msg, "groupType", 0x80000004);
794 container = "Users";
795 obj_class = "group";
797 if (add) {
798 ldb_msg_add_string(msg, "objectClass", obj_class);
799 msg->dn = ldb_dn_copy(mem_ctx, state->base_dn[database]);
800 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container);
801 if (!msg->dn) {
802 return NT_STATUS_NO_MEMORY;
805 ret = ldb_add(state->sam_ldb, msg);
806 if (ret != LDB_SUCCESS) {
807 *error_string = talloc_asprintf(mem_ctx, "Failed to create alias record %s: %s",
808 ldb_dn_get_linearized(msg->dn),
809 ldb_errstring(state->sam_ldb));
810 return NT_STATUS_INTERNAL_DB_CORRUPTION;
812 } else {
813 ret = dsdb_replace(state->sam_ldb, msg, 0);
814 if (ret != LDB_SUCCESS) {
815 *error_string = talloc_asprintf(mem_ctx, "Failed to modify alias record %s: %s",
816 ldb_dn_get_linearized(msg->dn),
817 ldb_errstring(state->sam_ldb));
818 return NT_STATUS_INTERNAL_DB_CORRUPTION;
822 return NT_STATUS_OK;
825 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
826 struct samsync_ldb_state *state,
827 enum netr_SamDatabaseID database,
828 struct netr_DELTA_ENUM *delta,
829 char **error_string)
831 uint32_t rid = delta->delta_id_union.rid;
832 struct ldb_message **msgs;
833 int ret;
834 const char *attrs[] = { NULL };
836 /* search for the alias, by rid */
837 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
838 "(&(objectClass=group)(objectSid=%s))",
839 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
841 if (ret == -1) {
842 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
843 return NT_STATUS_INTERNAL_DB_CORRUPTION;
844 } else if (ret == 0) {
845 return NT_STATUS_NO_SUCH_ALIAS;
846 } else if (ret > 1) {
847 return NT_STATUS_INTERNAL_DB_CORRUPTION;
850 ret = ldb_delete(state->sam_ldb, msgs[0]->dn);
851 if (ret != LDB_SUCCESS) {
852 *error_string = talloc_asprintf(mem_ctx, "Failed to delete alias record %s: %s",
853 ldb_dn_get_linearized(msgs[0]->dn),
854 ldb_errstring(state->sam_ldb));
855 return NT_STATUS_INTERNAL_DB_CORRUPTION;
858 return NT_STATUS_OK;
861 static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
862 struct samsync_ldb_state *state,
863 enum netr_SamDatabaseID database,
864 struct netr_DELTA_ENUM *delta,
865 char **error_string)
867 uint32_t rid = delta->delta_id_union.rid;
868 struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
869 struct ldb_message *msg;
870 struct ldb_message **msgs;
871 int ret;
872 const char *attrs[] = { NULL };
873 uint32_t i;
875 msg = ldb_msg_new(mem_ctx);
876 if (msg == NULL) {
877 return NT_STATUS_NO_MEMORY;
880 /* search for the alias, by rid */
881 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
882 "(&(objectClass=group)(objectSid=%s))",
883 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
885 if (ret == -1) {
886 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
887 return NT_STATUS_INTERNAL_DB_CORRUPTION;
888 } else if (ret == 0) {
889 return NT_STATUS_NO_SUCH_GROUP;
890 } else if (ret > 1) {
891 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s",
892 dom_sid_string(mem_ctx,
893 dom_sid_add_rid(mem_ctx,
894 state->dom_sid[database],
895 rid)));
896 return NT_STATUS_INTERNAL_DB_CORRUPTION;
897 } else {
898 msg->dn = talloc_steal(msg, msgs[0]->dn);
901 talloc_free(msgs);
903 for (i=0; i<alias_member->sids.num_sids; i++) {
904 struct ldb_dn *alias_member_dn;
905 const char *str_dn;
906 /* search for members, in the top basedn (normal users are builtin aliases) */
907 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
908 "(objectSid=%s)",
909 ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid));
911 if (ret == -1) {
912 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
913 return NT_STATUS_INTERNAL_DB_CORRUPTION;
914 } else if (ret == 0) {
915 NTSTATUS nt_status;
916 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
917 alias_member->sids.sids[i].sid,
918 &alias_member_dn,
919 error_string);
920 if (!NT_STATUS_IS_OK(nt_status)) {
921 return nt_status;
923 } else if (ret > 1) {
924 return NT_STATUS_INTERNAL_DB_CORRUPTION;
925 } else {
926 alias_member_dn = msgs[0]->dn;
928 str_dn = ldb_dn_alloc_linearized(msg, alias_member_dn);
929 NT_STATUS_HAVE_NO_MEMORY(str_dn);
930 ret = ldb_msg_add_string(msg, "member", str_dn);
931 if (ret != LDB_SUCCESS) return NT_STATUS_NO_MEMORY;
933 talloc_free(msgs);
936 ret = dsdb_replace(state->sam_ldb, msg, 0);
937 if (ret != LDB_SUCCESS) {
938 *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
939 ldb_dn_get_linearized(msg->dn),
940 ldb_errstring(state->sam_ldb));
941 return NT_STATUS_INTERNAL_DB_CORRUPTION;
944 return NT_STATUS_OK;
947 static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
948 struct samsync_ldb_state *state,
949 enum netr_SamDatabaseID database,
950 struct netr_DELTA_ENUM *delta,
951 char **error_string)
953 struct dom_sid *sid = delta->delta_id_union.sid;
954 struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
956 struct ldb_message *msg;
957 int ret;
958 uint32_t i;
959 char *dnstr, *sidstr;
961 msg = ldb_msg_new(mem_ctx);
962 if (msg == NULL) {
963 return NT_STATUS_NO_MEMORY;
966 sidstr = dom_sid_string(msg, sid);
967 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sidstr, msg);
969 dnstr = talloc_asprintf(msg, "sid=%s", sidstr);
970 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(dnstr, msg);
972 msg->dn = ldb_dn_new(msg, state->pdb, dnstr);
973 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(msg->dn, msg);
975 for (i=0; i< account->privilege_entries; i++) {
976 ldb_msg_add_string(msg, "privilege", account->privilege_name[i].string);
979 ret = dsdb_replace(state->pdb, msg, 0);
980 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
981 if (samdb_msg_add_dom_sid(state->pdb, msg, msg, "objectSid", sid) != LDB_SUCCESS) {
982 talloc_free(msg);
983 return NT_STATUS_NO_MEMORY;
985 ldb_msg_add_string(msg, "comment", "added via samsync");
986 ret = ldb_add(state->pdb, msg);
989 if (ret != LDB_SUCCESS) {
990 *error_string = talloc_asprintf(mem_ctx, "Failed to modify privilege record %s",
991 ldb_dn_get_linearized(msg->dn));
992 return NT_STATUS_INTERNAL_DB_CORRUPTION;
995 return NT_STATUS_OK;
998 static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
999 struct samsync_ldb_state *state,
1000 enum netr_SamDatabaseID database,
1001 struct netr_DELTA_ENUM *delta,
1002 char **error_string)
1004 struct dom_sid *sid = delta->delta_id_union.sid;
1006 struct ldb_message *msg;
1007 struct ldb_message **msgs;
1008 int ret;
1009 const char *attrs[] = { NULL };
1011 msg = ldb_msg_new(mem_ctx);
1012 if (msg == NULL) {
1013 return NT_STATUS_NO_MEMORY;
1016 /* search for the account, by sid, in the top basedn */
1017 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
1018 "(objectSid=%s)",
1019 ldap_encode_ndr_dom_sid(mem_ctx, sid));
1021 if (ret == -1) {
1022 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
1023 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1024 } else if (ret == 0) {
1025 return NT_STATUS_NO_SUCH_USER;
1026 } else if (ret > 1) {
1027 *error_string = talloc_asprintf(mem_ctx, "More than one account with SID: %s",
1028 dom_sid_string(mem_ctx, sid));
1029 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1030 } else {
1031 msg->dn = talloc_steal(msg, msgs[0]->dn);
1034 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
1035 "privilege");
1037 ret = dsdb_replace(state->sam_ldb, msg, 0);
1038 if (ret != LDB_SUCCESS) {
1039 *error_string = talloc_asprintf(mem_ctx, "Failed to modify privilege record %s",
1040 ldb_dn_get_linearized(msg->dn));
1041 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1044 return NT_STATUS_OK;
1047 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,
1048 void *private_data,
1049 enum netr_SamDatabaseID database,
1050 struct netr_DELTA_ENUM *delta,
1051 char **error_string)
1053 NTSTATUS nt_status = NT_STATUS_OK;
1054 struct samsync_ldb_state *state = talloc_get_type(private_data, struct samsync_ldb_state);
1056 *error_string = NULL;
1057 switch (delta->delta_type) {
1058 case NETR_DELTA_DOMAIN:
1060 nt_status = samsync_ldb_handle_domain(mem_ctx,
1061 state,
1062 database,
1063 delta,
1064 error_string);
1065 break;
1067 case NETR_DELTA_USER:
1069 nt_status = samsync_ldb_handle_user(mem_ctx,
1070 state,
1071 database,
1072 delta,
1073 error_string);
1074 break;
1076 case NETR_DELTA_DELETE_USER:
1078 nt_status = samsync_ldb_delete_user(mem_ctx,
1079 state,
1080 database,
1081 delta,
1082 error_string);
1083 break;
1085 case NETR_DELTA_GROUP:
1087 nt_status = samsync_ldb_handle_group(mem_ctx,
1088 state,
1089 database,
1090 delta,
1091 error_string);
1092 break;
1094 case NETR_DELTA_DELETE_GROUP:
1096 nt_status = samsync_ldb_delete_group(mem_ctx,
1097 state,
1098 database,
1099 delta,
1100 error_string);
1101 break;
1103 case NETR_DELTA_GROUP_MEMBER:
1105 nt_status = samsync_ldb_handle_group_member(mem_ctx,
1106 state,
1107 database,
1108 delta,
1109 error_string);
1110 break;
1112 case NETR_DELTA_ALIAS:
1114 nt_status = samsync_ldb_handle_alias(mem_ctx,
1115 state,
1116 database,
1117 delta,
1118 error_string);
1119 break;
1121 case NETR_DELTA_DELETE_ALIAS:
1123 nt_status = samsync_ldb_delete_alias(mem_ctx,
1124 state,
1125 database,
1126 delta,
1127 error_string);
1128 break;
1130 case NETR_DELTA_ALIAS_MEMBER:
1132 nt_status = samsync_ldb_handle_alias_member(mem_ctx,
1133 state,
1134 database,
1135 delta,
1136 error_string);
1137 break;
1139 case NETR_DELTA_ACCOUNT:
1141 nt_status = samsync_ldb_handle_account(mem_ctx,
1142 state,
1143 database,
1144 delta,
1145 error_string);
1146 break;
1148 case NETR_DELTA_DELETE_ACCOUNT:
1150 nt_status = samsync_ldb_delete_account(mem_ctx,
1151 state,
1152 database,
1153 delta,
1154 error_string);
1155 break;
1157 default:
1158 /* Can't dump them all right now */
1159 break;
1161 if (!NT_STATUS_IS_OK(nt_status) && !*error_string) {
1162 *error_string = talloc_asprintf(mem_ctx, "Failed to handle samsync delta: %s", nt_errstr(nt_status));
1164 return nt_status;
1167 static NTSTATUS libnet_samsync_ldb_init(TALLOC_CTX *mem_ctx,
1168 void *private_data,
1169 struct libnet_SamSync_state *samsync_state,
1170 char **error_string)
1172 struct samsync_ldb_state *state = talloc_get_type(private_data, struct samsync_ldb_state);
1173 const char *server = dcerpc_server_name(samsync_state->netlogon_pipe);
1174 char *ldap_url;
1176 state->samsync_state = samsync_state;
1178 ZERO_STRUCT(state->dom_sid);
1179 if (state->samsync_state->domain_sid) {
1180 state->dom_sid[SAM_DATABASE_DOMAIN] = dom_sid_dup(state, state->samsync_state->domain_sid);
1183 state->dom_sid[SAM_DATABASE_BUILTIN] = dom_sid_parse_talloc(state, SID_BUILTIN);
1185 if (state->samsync_state->realm) {
1186 if (!server || !*server) {
1187 /* huh? how do we not have a server name? */
1188 *error_string = talloc_strdup(mem_ctx, "No DCE/RPC server name available. How did we connect?");
1189 return NT_STATUS_INVALID_PARAMETER;
1191 ldap_url = talloc_asprintf(state, "ldap://%s", server);
1193 state->remote_ldb = ldb_wrap_connect(mem_ctx,
1194 NULL,
1195 state->samsync_state->machine_net_ctx->lp_ctx,
1196 ldap_url,
1197 NULL, state->samsync_state->machine_net_ctx->cred,
1199 if (!state->remote_ldb) {
1200 *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);
1201 return NT_STATUS_NO_LOGON_SERVERS;
1203 } else {
1204 state->remote_ldb = NULL;
1206 return NT_STATUS_OK;
1209 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1211 NTSTATUS nt_status;
1212 struct libnet_SamSync r2;
1213 struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
1215 if (!state) {
1216 return NT_STATUS_NO_MEMORY;
1219 state->secrets = NULL;
1220 state->trusted_domains = NULL;
1222 state->sam_ldb = samdb_connect(mem_ctx,
1223 ctx->event_ctx,
1224 ctx->lp_ctx,
1225 r->in.session_info,
1227 if (!state->sam_ldb) {
1228 return NT_STATUS_INTERNAL_DB_ERROR;
1231 state->pdb = privilege_connect(mem_ctx,
1232 ctx->lp_ctx);
1233 if (!state->pdb) {
1234 return NT_STATUS_INTERNAL_DB_ERROR;
1237 r2.out.error_string = NULL;
1238 r2.in.binding_string = r->in.binding_string;
1239 r2.in.init_fn = libnet_samsync_ldb_init;
1240 r2.in.delta_fn = libnet_samsync_ldb_fn;
1241 r2.in.fn_ctx = state;
1242 r2.in.machine_account = NULL; /* TODO: Create a machine account, fill this in, and the delete it */
1243 nt_status = libnet_SamSync_netlogon(ctx, state, &r2);
1244 r->out.error_string = r2.out.error_string;
1245 talloc_steal(mem_ctx, r->out.error_string);
1247 if (!NT_STATUS_IS_OK(nt_status)) {
1248 talloc_free(state);
1249 return nt_status;
1251 talloc_free(state);
1252 return nt_status;