r9949: Portability fixes for mingw32
[Samba/aatanasov.git] / source / libnet / libnet_samsync_ldb.c
blob837170afac660972433a4cdf09145dfe0306cc0c
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 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "includes.h"
27 #include "libnet/libnet.h"
28 #include "librpc/gen_ndr/ndr_netlogon.h"
29 #include "librpc/gen_ndr/ndr_samr.h"
30 #include "dlinklist.h"
31 #include "lib/ldb/include/ldb.h"
33 struct samsync_ldb_secret {
34 struct samsync_ldb_secret *prev, *next;
35 DATA_BLOB secret;
36 char *name;
37 NTTIME mtime;
40 struct samsync_ldb_trusted_domain {
41 struct samsync_ldb_trusted_domain *prev, *next;
42 struct dom_sid *sid;
43 char *name;
46 struct samsync_ldb_state {
47 struct dom_sid *dom_sid[3];
48 struct ldb_context *sam_ldb;
49 struct ldb_dn *base_dn[3];
50 struct samsync_ldb_secret *secrets;
51 struct samsync_ldb_trusted_domain *trusted_domains;
54 static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,
55 struct samsync_ldb_state *state,
56 struct dom_sid *sid,
57 struct ldb_dn **fsp_dn)
59 const char *sidstr = dom_sid_string(mem_ctx, sid);
60 /* We assume that ForeignSecurityPrincipals are under the BASEDN of the main domain */
61 struct ldb_dn *basedn = samdb_search_dn(state->sam_ldb, mem_ctx,
62 state->base_dn[SAM_DATABASE_DOMAIN],
63 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
64 struct ldb_message *msg;
65 int ret;
67 if (!sidstr) {
68 return NT_STATUS_NO_MEMORY;
71 if (basedn == NULL) {
72 DEBUG(0, ("Failed to find DN for "
73 "ForeignSecurityPrincipal container\n"));
74 return NT_STATUS_INTERNAL_DB_CORRUPTION;
77 msg = ldb_msg_new(mem_ctx);
78 if (msg == NULL) {
79 return NT_STATUS_NO_MEMORY;
82 /* add core elements to the ldb_message for the alias */
83 msg->dn = ldb_dn_build_child(mem_ctx, "CN", sidstr, basedn);
84 if (msg->dn == NULL)
85 return NT_STATUS_NO_MEMORY;
87 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
88 "objectClass",
89 "foreignSecurityPrincipal");
91 *fsp_dn = msg->dn;
93 /* create the alias */
94 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
95 if (ret != 0) {
96 DEBUG(0,("Failed to create foreignSecurityPrincipal "
97 "record %s: %s\n",
98 ldb_dn_linearize(mem_ctx, msg->dn),
99 ldb_errstring(state->sam_ldb)));
100 return NT_STATUS_INTERNAL_DB_CORRUPTION;
102 return NT_STATUS_OK;
105 static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
106 struct samsync_ldb_state *state,
107 struct creds_CredentialState *creds,
108 enum netr_SamDatabaseID database,
109 struct netr_DELTA_ENUM *delta)
111 struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;
112 const char *domain_name = domain->domain_name.string;
113 struct ldb_message *msg;
114 int ret;
116 if (database == SAM_DATABASE_DOMAIN) {
117 const char *domain_attrs[] = {"nETBIOSName", "nCName", NULL};
118 struct ldb_message **msgs_domain;
119 int ret_domain;
120 char *base_dn;
122 ret_domain = gendb_search(state->sam_ldb, mem_ctx, NULL, &msgs_domain, domain_attrs,
123 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
124 domain_name);
125 if (ret_domain == -1) {
126 return NT_STATUS_INTERNAL_DB_CORRUPTION;
129 if (ret_domain != 1) {
130 return NT_STATUS_NO_SUCH_DOMAIN;
133 state->base_dn[database] = samdb_result_dn(state, msgs_domain[0], "nCName", NULL);
135 base_dn = ldb_dn_linearize(mem_ctx, state->base_dn[database]);
137 state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state,
138 state->base_dn[database],
139 "objectSid", "dn=%s", base_dn);
140 } else if (database == SAM_DATABASE_BUILTIN) {
141 /* work out the builtin_dn - useful for so many calls its worth
142 fetching here */
143 const char *dnstring = samdb_search_string(state->sam_ldb, mem_ctx, NULL,
144 "dn", "objectClass=builtinDomain");
145 state->base_dn[database] = ldb_dn_explode(state, dnstring);
146 state->dom_sid[database] = dom_sid_parse_talloc(state, SID_BUILTIN);
147 } else {
148 /* PRIVs DB */
149 return NT_STATUS_INVALID_PARAMETER;
152 msg = ldb_msg_new(mem_ctx);
153 if (msg == NULL) {
154 return NT_STATUS_NO_MEMORY;
157 msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
158 if (!msg->dn) {
159 return NT_STATUS_NO_MEMORY;
162 samdb_msg_add_string(state->sam_ldb, mem_ctx,
163 msg, "oEMInformation", domain->comment.string);
165 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
166 msg, "forceLogoff", domain->force_logoff_time);
168 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
169 msg, "minPwdLen", domain->min_password_length);
171 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
172 msg, "maxPwdAge", domain->max_password_age);
174 samdb_msg_add_int64(state->sam_ldb, mem_ctx,
175 msg, "minPwdAge", domain->min_password_age);
177 samdb_msg_add_uint(state->sam_ldb, mem_ctx,
178 msg, "pwdHistoryLength", domain->password_history_length);
180 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
181 msg, "modifiedCount",
182 domain->sequence_num);
184 samdb_msg_add_uint64(state->sam_ldb, mem_ctx,
185 msg, "creationTime", domain->domain_create_time);
187 /* TODO: Account lockout, password properties */
189 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
191 if (ret) {
192 return NT_STATUS_INTERNAL_ERROR;
194 return NT_STATUS_OK;
197 static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
198 struct samsync_ldb_state *state,
199 struct creds_CredentialState *creds,
200 enum netr_SamDatabaseID database,
201 struct netr_DELTA_ENUM *delta)
203 uint32_t rid = delta->delta_id_union.rid;
204 struct netr_DELTA_USER *user = delta->delta_union.user;
205 const char *container, *obj_class;
206 char *cn_name;
207 int cn_name_len;
209 struct ldb_message *msg;
210 struct ldb_message **msgs;
211 int ret;
212 uint32_t acb;
213 BOOL add = False;
214 const char *attrs[] = { NULL };
216 msg = ldb_msg_new(mem_ctx);
217 if (msg == NULL) {
218 return NT_STATUS_NO_MEMORY;
221 /* search for the user, by rid */
222 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
223 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
224 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
226 if (ret == -1) {
227 return NT_STATUS_INTERNAL_DB_CORRUPTION;
228 } else if (ret == 0) {
229 add = True;
230 } else if (ret > 1) {
231 DEBUG(0, ("More than one user with SID: %s\n",
232 dom_sid_string(mem_ctx,
233 dom_sid_add_rid(mem_ctx,
234 state->dom_sid[database],
235 rid))));
236 return NT_STATUS_INTERNAL_DB_CORRUPTION;
237 } else {
238 msg->dn = talloc_steal(msg, msgs[0]->dn);
242 cn_name = talloc_strdup(mem_ctx, user->account_name.string);
243 NT_STATUS_HAVE_NO_MEMORY(cn_name);
244 cn_name_len = strlen(cn_name);
246 #define ADD_OR_DEL(type, attrib, field) do {\
247 if (user->field) { \
248 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
249 attrib, user->field); \
250 } else if (!add) { \
251 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
252 attrib); \
254 } while (0);
256 ADD_OR_DEL(string, "samAccountName", account_name.string);
257 ADD_OR_DEL(string, "displayName", full_name.string);
259 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
260 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
261 return NT_STATUS_NO_MEMORY;
264 ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
265 ADD_OR_DEL(string, "homeDirectory", home_directory.string);
266 ADD_OR_DEL(string, "homeDrive", home_drive.string);
267 ADD_OR_DEL(string, "scriptPath", logon_script.string);
268 ADD_OR_DEL(string, "description", description.string);
269 ADD_OR_DEL(string, "userWorkstations", workstations.string);
271 ADD_OR_DEL(uint64, "lastLogon", last_logon);
272 ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
274 if (samdb_msg_add_logon_hours(state->sam_ldb, mem_ctx, msg, "logonHours", &user->logon_hours) != 0) {
275 return NT_STATUS_NO_MEMORY;
278 ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
279 ADD_OR_DEL(uint, "logonCount", logon_count);
281 ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
282 ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
284 if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg,
285 "userAccountControl", user->acct_flags) != 0) {
286 return NT_STATUS_NO_MEMORY;
289 /* Passwords */
290 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
291 "unicodePwd");
292 if (user->lm_password_present) {
293 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
294 "lmPwdHash", &user->lmpassword);
295 } else {
296 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
297 "lmPwdHash");
299 if (user->nt_password_present) {
300 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,
301 "ntPwdHash", &user->ntpassword);
302 } else {
303 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
304 "ntPwdHash");
307 ADD_OR_DEL(string, "comment", comment.string);
308 ADD_OR_DEL(string, "userParameters", parameters.string);
309 ADD_OR_DEL(uint, "countryCode", country_code);
310 ADD_OR_DEL(uint, "codePage", code_page);
312 ADD_OR_DEL(string, "profilePath", profile_path.string);
314 #undef ADD_OR_DEL
316 acb = user->acct_flags;
317 if (acb & (ACB_WSTRUST)) {
318 cn_name[cn_name_len - 1] = '\0';
319 container = "Computers";
320 obj_class = "computer";
322 } else if (acb & ACB_SVRTRUST) {
323 if (cn_name[cn_name_len - 1] != '$') {
324 return NT_STATUS_FOOBAR;
326 cn_name[cn_name_len - 1] = '\0';
327 container = "Domain Controllers";
328 obj_class = "computer";
329 } else {
330 container = "Users";
331 obj_class = "user";
333 if (add) {
334 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
335 "objectClass", obj_class);
336 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
337 "CN=%s, CN=%s", cn_name, container);
338 if (!msg->dn) {
339 return NT_STATUS_NO_MEMORY;
342 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
343 if (ret != 0) {
344 DEBUG(0,("Failed to create user record %s\n",
345 ldb_dn_linearize(mem_ctx, msg->dn)));
346 return NT_STATUS_INTERNAL_DB_CORRUPTION;
348 } else {
349 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
350 if (ret != 0) {
351 DEBUG(0,("Failed to modify user record %s\n",
352 ldb_dn_linearize(mem_ctx, msg->dn)));
353 return NT_STATUS_INTERNAL_DB_CORRUPTION;
357 return NT_STATUS_OK;
360 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
361 struct samsync_ldb_state *state,
362 struct creds_CredentialState *creds,
363 enum netr_SamDatabaseID database,
364 struct netr_DELTA_ENUM *delta)
366 uint32_t rid = delta->delta_id_union.rid;
367 struct ldb_message **msgs;
368 int ret;
369 const char *attrs[] = { NULL };
371 /* search for the user, by rid */
372 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
373 &msgs, attrs, "(&(objectClass=user)(objectSid=%s))",
374 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
376 if (ret == -1) {
377 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
378 return NT_STATUS_INTERNAL_DB_CORRUPTION;
379 } else if (ret == 0) {
380 return NT_STATUS_NO_SUCH_USER;
381 } else if (ret > 1) {
382 DEBUG(0, ("More than one user with SID: %s\n",
383 dom_sid_string(mem_ctx,
384 dom_sid_add_rid(mem_ctx,
385 state->dom_sid[database],
386 rid))));
387 return NT_STATUS_INTERNAL_DB_CORRUPTION;
390 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
391 if (ret != 0) {
392 DEBUG(0,("Failed to delete user record %s: %s\n",
393 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
394 ldb_errstring(state->sam_ldb)));
395 return NT_STATUS_INTERNAL_DB_CORRUPTION;
398 return NT_STATUS_OK;
401 static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
402 struct samsync_ldb_state *state,
403 struct creds_CredentialState *creds,
404 enum netr_SamDatabaseID database,
405 struct netr_DELTA_ENUM *delta)
407 uint32_t rid = delta->delta_id_union.rid;
408 struct netr_DELTA_GROUP *group = delta->delta_union.group;
409 const char *container, *obj_class;
410 const char *cn_name;
412 struct ldb_message *msg;
413 struct ldb_message **msgs;
414 int ret;
415 BOOL add = False;
416 const char *attrs[] = { NULL };
418 msg = ldb_msg_new(mem_ctx);
419 if (msg == NULL) {
420 return NT_STATUS_NO_MEMORY;
423 /* search for the group, by rid */
424 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
425 "(&(objectClass=group)(objectSid=%s))",
426 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
428 if (ret == -1) {
429 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
430 return NT_STATUS_INTERNAL_DB_CORRUPTION;
431 } else if (ret == 0) {
432 add = True;
433 } else if (ret > 1) {
434 DEBUG(0, ("More than one group/alias with SID: %s\n",
435 dom_sid_string(mem_ctx,
436 dom_sid_add_rid(mem_ctx,
437 state->dom_sid[database],
438 rid))));
439 return NT_STATUS_INTERNAL_DB_CORRUPTION;
440 } else {
441 msg->dn = talloc_steal(msg, msgs[0]->dn);
444 cn_name = group->group_name.string;
446 #define ADD_OR_DEL(type, attrib, field) do {\
447 if (group->field) { \
448 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
449 attrib, group->field); \
450 } else if (!add) { \
451 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
452 attrib); \
454 } while (0);
456 ADD_OR_DEL(string, "samAccountName", group_name.string);
458 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
459 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
460 return NT_STATUS_NO_MEMORY;
463 ADD_OR_DEL(string, "description", description.string);
465 #undef ADD_OR_DEL
467 container = "Users";
468 obj_class = "group";
470 if (add) {
471 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
472 "objectClass", obj_class);
473 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
474 "CN=%s, CN=%s", cn_name, container);
475 if (!msg->dn) {
476 return NT_STATUS_NO_MEMORY;
479 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
480 if (ret != 0) {
481 DEBUG(0,("Failed to create group record %s: %s\n",
482 ldb_dn_linearize(mem_ctx, msg->dn),
483 ldb_errstring(state->sam_ldb)));
484 return NT_STATUS_INTERNAL_DB_CORRUPTION;
486 } else {
487 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
488 if (ret != 0) {
489 DEBUG(0,("Failed to modify group record %s: %s\n",
490 ldb_dn_linearize(mem_ctx, msg->dn),
491 ldb_errstring(state->sam_ldb)));
492 return NT_STATUS_INTERNAL_DB_CORRUPTION;
496 return NT_STATUS_OK;
499 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
500 struct samsync_ldb_state *state,
501 struct creds_CredentialState *creds,
502 enum netr_SamDatabaseID database,
503 struct netr_DELTA_ENUM *delta)
505 uint32_t rid = delta->delta_id_union.rid;
506 struct ldb_message **msgs;
507 int ret;
508 const char *attrs[] = { NULL };
510 /* search for the group, by rid */
511 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
512 "(&(objectClass=group)(objectSid=%s))",
513 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
515 if (ret == -1) {
516 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
517 return NT_STATUS_INTERNAL_DB_CORRUPTION;
518 } else if (ret == 0) {
519 return NT_STATUS_NO_SUCH_GROUP;
520 } else if (ret > 1) {
521 DEBUG(0, ("More than one group/alias with SID: %s\n",
522 dom_sid_string(mem_ctx,
523 dom_sid_add_rid(mem_ctx,
524 state->dom_sid[database],
525 rid))));
526 return NT_STATUS_INTERNAL_DB_CORRUPTION;
529 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
530 if (ret != 0) {
531 DEBUG(0,("Failed to delete group record %s: %s\n",
532 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
533 ldb_errstring(state->sam_ldb)));
534 return NT_STATUS_INTERNAL_DB_CORRUPTION;
537 return NT_STATUS_OK;
540 static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
541 struct samsync_ldb_state *state,
542 struct creds_CredentialState *creds,
543 enum netr_SamDatabaseID database,
544 struct netr_DELTA_ENUM *delta)
546 uint32_t rid = delta->delta_id_union.rid;
547 struct netr_DELTA_GROUP_MEMBER *group_member = delta->delta_union.group_member;
548 struct ldb_message *msg;
549 struct ldb_message **msgs;
550 int ret;
551 const char *attrs[] = { NULL };
552 int i;
554 msg = ldb_msg_new(mem_ctx);
555 if (msg == NULL) {
556 return NT_STATUS_NO_MEMORY;
559 /* search for the group, by rid */
560 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
561 "(&(objectClass=group)(objectSid=%s))",
562 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
564 if (ret == -1) {
565 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
566 return NT_STATUS_INTERNAL_DB_CORRUPTION;
567 } else if (ret == 0) {
568 return NT_STATUS_NO_SUCH_GROUP;
569 } else if (ret > 1) {
570 DEBUG(0, ("More than one group/alias with SID: %s\n",
571 dom_sid_string(mem_ctx,
572 dom_sid_add_rid(mem_ctx,
573 state->dom_sid[database],
574 rid))));
575 return NT_STATUS_INTERNAL_DB_CORRUPTION;
576 } else {
577 msg->dn = talloc_steal(msg, msgs[0]->dn);
580 talloc_free(msgs);
582 for (i=0; i<group_member->num_rids; i++) {
583 /* search for the group, by rid */
584 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
585 "(&(objectClass=user)(objectSid=%s))",
586 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], group_member->rids[i])));
588 if (ret == -1) {
589 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
590 return NT_STATUS_INTERNAL_DB_CORRUPTION;
591 } else if (ret == 0) {
592 return NT_STATUS_NO_SUCH_USER;
593 } else if (ret > 1) {
594 return NT_STATUS_INTERNAL_DB_CORRUPTION;
595 } else {
596 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, msgs[0]->dn));
599 talloc_free(msgs);
602 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
603 if (ret != 0) {
604 DEBUG(0,("Failed to modify group record %s: %s\n",
605 ldb_dn_linearize(mem_ctx, msg->dn),
606 ldb_errstring(state->sam_ldb)));
607 return NT_STATUS_INTERNAL_DB_CORRUPTION;
610 return NT_STATUS_OK;
613 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
614 struct samsync_ldb_state *state,
615 struct creds_CredentialState *creds,
616 enum netr_SamDatabaseID database,
617 struct netr_DELTA_ENUM *delta)
619 uint32_t rid = delta->delta_id_union.rid;
620 struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
621 const char *container, *obj_class;
622 const char *cn_name;
624 struct ldb_message *msg;
625 struct ldb_message **msgs;
626 int ret;
627 BOOL add = False;
628 const char *attrs[] = { NULL };
630 msg = ldb_msg_new(mem_ctx);
631 if (msg == NULL) {
632 return NT_STATUS_NO_MEMORY;
635 /* search for the alias, by rid */
636 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
637 "(&(objectClass=group)(objectSid=%s))",
638 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
640 if (ret == -1) {
641 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
642 return NT_STATUS_INTERNAL_DB_CORRUPTION;
643 } else if (ret == 0) {
644 add = True;
645 } else if (ret > 1) {
646 DEBUG(0, ("More than one group/alias with SID: %s\n",
647 dom_sid_string(mem_ctx,
648 dom_sid_add_rid(mem_ctx,
649 state->dom_sid[database],
650 rid))));
651 return NT_STATUS_INTERNAL_DB_CORRUPTION;
652 } else {
653 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
656 cn_name = alias->alias_name.string;
658 #define ADD_OR_DEL(type, attrib, field) do {\
659 if (alias->field) { \
660 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
661 attrib, alias->field); \
662 } else if (!add) { \
663 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
664 attrib); \
666 } while (0);
668 ADD_OR_DEL(string, "samAccountName", alias_name.string);
670 if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg,
671 "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
672 return NT_STATUS_NO_MEMORY;
675 ADD_OR_DEL(string, "description", description.string);
677 #undef ADD_OR_DEL
679 samdb_msg_add_uint(state->sam_ldb, mem_ctx, msg, "groupType", 0x80000004);
681 container = "Users";
682 obj_class = "group";
684 if (add) {
685 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
686 "objectClass", obj_class);
687 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
688 "CN=%s, CN=%s", cn_name, container);
689 if (!msg->dn) {
690 return NT_STATUS_NO_MEMORY;
693 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
694 if (ret != 0) {
695 DEBUG(0,("Failed to create alias record %s: %s\n",
696 ldb_dn_linearize(mem_ctx, msg->dn),
697 ldb_errstring(state->sam_ldb)));
698 return NT_STATUS_INTERNAL_DB_CORRUPTION;
700 } else {
701 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
702 if (ret != 0) {
703 DEBUG(0,("Failed to modify alias record %s: %s\n",
704 ldb_dn_linearize(mem_ctx, msg->dn),
705 ldb_errstring(state->sam_ldb)));
706 return NT_STATUS_INTERNAL_DB_CORRUPTION;
710 return NT_STATUS_OK;
713 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
714 struct samsync_ldb_state *state,
715 struct creds_CredentialState *creds,
716 enum netr_SamDatabaseID database,
717 struct netr_DELTA_ENUM *delta)
719 uint32_t rid = delta->delta_id_union.rid;
720 struct ldb_message **msgs;
721 int ret;
722 const char *attrs[] = { NULL };
724 /* search for the alias, by rid */
725 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
726 "(&(objectClass=group)(objectSid=%s))",
727 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
729 if (ret == -1) {
730 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
731 return NT_STATUS_INTERNAL_DB_CORRUPTION;
732 } else if (ret == 0) {
733 return NT_STATUS_NO_SUCH_ALIAS;
734 } else if (ret > 1) {
735 return NT_STATUS_INTERNAL_DB_CORRUPTION;
738 ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
739 if (ret != 0) {
740 DEBUG(0,("Failed to delete alias record %s: %s\n",
741 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
742 ldb_errstring(state->sam_ldb)));
743 return NT_STATUS_INTERNAL_DB_CORRUPTION;
746 return NT_STATUS_OK;
749 static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
750 struct samsync_ldb_state *state,
751 struct creds_CredentialState *creds,
752 enum netr_SamDatabaseID database,
753 struct netr_DELTA_ENUM *delta)
755 uint32_t rid = delta->delta_id_union.rid;
756 struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
757 struct ldb_message *msg;
758 struct ldb_message **msgs;
759 int ret;
760 const char *attrs[] = { NULL };
761 int i;
763 msg = ldb_msg_new(mem_ctx);
764 if (msg == NULL) {
765 return NT_STATUS_NO_MEMORY;
768 /* search for the alias, by rid */
769 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
770 "(&(objectClass=group)(objectSid=%s))",
771 ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid)));
773 if (ret == -1) {
774 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
775 return NT_STATUS_INTERNAL_DB_CORRUPTION;
776 } else if (ret == 0) {
777 return NT_STATUS_NO_SUCH_GROUP;
778 } else if (ret > 1) {
779 DEBUG(0, ("More than one group/alias with SID: %s\n",
780 dom_sid_string(mem_ctx,
781 dom_sid_add_rid(mem_ctx,
782 state->dom_sid[database],
783 rid))));
784 return NT_STATUS_INTERNAL_DB_CORRUPTION;
785 } else {
786 msg->dn = talloc_steal(msg, msgs[0]->dn);
789 talloc_free(msgs);
791 for (i=0; i<alias_member->sids.num_sids; i++) {
792 struct ldb_dn *alias_member_dn;
793 /* search for members, in the top basedn (normal users are builtin aliases) */
794 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
795 "(objectSid=%s)",
796 ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid));
798 if (ret == -1) {
799 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
800 return NT_STATUS_INTERNAL_DB_CORRUPTION;
801 } else if (ret == 0) {
802 NTSTATUS nt_status;
803 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
804 alias_member->sids.sids[i].sid,
805 &alias_member_dn);
806 if (!NT_STATUS_IS_OK(nt_status)) {
807 return nt_status;
809 } else if (ret > 1) {
810 return NT_STATUS_INTERNAL_DB_CORRUPTION;
811 } else {
812 alias_member_dn = msgs[0]->dn;
814 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, alias_member_dn));
816 talloc_free(msgs);
819 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
820 if (ret != 0) {
821 DEBUG(0,("Failed to modify group record %s: %s\n",
822 ldb_dn_linearize(mem_ctx, msg->dn),
823 ldb_errstring(state->sam_ldb)));
824 return NT_STATUS_INTERNAL_DB_CORRUPTION;
827 return NT_STATUS_OK;
830 static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
831 struct samsync_ldb_state *state,
832 struct creds_CredentialState *creds,
833 enum netr_SamDatabaseID database,
834 struct netr_DELTA_ENUM *delta)
836 struct dom_sid *sid = delta->delta_id_union.sid;
837 struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
839 struct ldb_message *msg;
840 struct ldb_message **msgs;
841 struct ldb_dn *privilege_dn;
842 int ret;
843 const char *attrs[] = { NULL };
844 int i;
846 msg = ldb_msg_new(mem_ctx);
847 if (msg == NULL) {
848 return NT_STATUS_NO_MEMORY;
851 /* search for the account, by sid, in the top basedn */
852 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
853 "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, sid));
855 if (ret == -1) {
856 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
857 return NT_STATUS_INTERNAL_DB_CORRUPTION;
858 } else if (ret == 0) {
859 NTSTATUS nt_status;
860 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
861 sid,
862 &privilege_dn);
863 privilege_dn = talloc_steal(msg, privilege_dn);
864 if (!NT_STATUS_IS_OK(nt_status)) {
865 return nt_status;
867 } else if (ret > 1) {
868 DEBUG(0, ("More than one account with SID: %s\n",
869 dom_sid_string(mem_ctx, sid)));
870 return NT_STATUS_INTERNAL_DB_CORRUPTION;
871 } else {
872 privilege_dn = talloc_steal(msg, msgs[0]->dn);
875 msg->dn = privilege_dn;
877 for (i=0; i< account->privilege_entries; i++) {
878 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "privilege",
879 account->privilege_name[i].string);
882 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
883 if (ret != 0) {
884 DEBUG(0,("Failed to modify privilege record %s\n",
885 ldb_dn_linearize(mem_ctx, msg->dn)));
886 return NT_STATUS_INTERNAL_DB_CORRUPTION;
889 return NT_STATUS_OK;
892 static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
893 struct samsync_ldb_state *state,
894 struct creds_CredentialState *creds,
895 enum netr_SamDatabaseID database,
896 struct netr_DELTA_ENUM *delta)
898 struct dom_sid *sid = delta->delta_id_union.sid;
900 struct ldb_message *msg;
901 struct ldb_message **msgs;
902 int ret;
903 const char *attrs[] = { NULL };
905 msg = ldb_msg_new(mem_ctx);
906 if (msg == NULL) {
907 return NT_STATUS_NO_MEMORY;
910 /* search for the account, by sid, in the top basedn */
911 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
912 "(objectSid=%s)",
913 ldap_encode_ndr_dom_sid(mem_ctx, sid));
915 if (ret == -1) {
916 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
917 return NT_STATUS_INTERNAL_DB_CORRUPTION;
918 } else if (ret == 0) {
919 return NT_STATUS_NO_SUCH_USER;
920 } else if (ret > 1) {
921 DEBUG(0, ("More than one account with SID: %s\n",
922 dom_sid_string(mem_ctx, sid)));
923 return NT_STATUS_INTERNAL_DB_CORRUPTION;
924 } else {
925 msg->dn = talloc_steal(msg, msgs[0]->dn);
928 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,
929 "privilage");
931 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
932 if (ret != 0) {
933 DEBUG(0,("Failed to modify privilege record %s\n",
934 ldb_dn_linearize(mem_ctx, msg->dn)));
935 return NT_STATUS_INTERNAL_DB_CORRUPTION;
938 return NT_STATUS_OK;
941 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,
942 void *private,
943 struct creds_CredentialState *creds,
944 enum netr_SamDatabaseID database,
945 struct netr_DELTA_ENUM *delta,
946 char **error_string)
948 NTSTATUS nt_status = NT_STATUS_OK;
949 struct samsync_ldb_state *state = private;
951 *error_string = NULL;
952 switch (delta->delta_type) {
953 case NETR_DELTA_DOMAIN:
955 nt_status = samsync_ldb_handle_domain(mem_ctx,
956 state,
957 creds,
958 database,
959 delta);
960 break;
962 case NETR_DELTA_USER:
964 nt_status = samsync_ldb_handle_user(mem_ctx,
965 state,
966 creds,
967 database,
968 delta);
969 break;
971 case NETR_DELTA_DELETE_USER:
973 nt_status = samsync_ldb_delete_user(mem_ctx,
974 state,
975 creds,
976 database,
977 delta);
978 break;
980 case NETR_DELTA_GROUP:
982 nt_status = samsync_ldb_handle_group(mem_ctx,
983 state,
984 creds,
985 database,
986 delta);
987 break;
989 case NETR_DELTA_DELETE_GROUP:
991 nt_status = samsync_ldb_delete_group(mem_ctx,
992 state,
993 creds,
994 database,
995 delta);
996 break;
998 case NETR_DELTA_GROUP_MEMBER:
1000 nt_status = samsync_ldb_handle_group_member(mem_ctx,
1001 state,
1002 creds,
1003 database,
1004 delta);
1005 break;
1007 case NETR_DELTA_ALIAS:
1009 nt_status = samsync_ldb_handle_alias(mem_ctx,
1010 state,
1011 creds,
1012 database,
1013 delta);
1014 break;
1016 case NETR_DELTA_DELETE_ALIAS:
1018 nt_status = samsync_ldb_delete_alias(mem_ctx,
1019 state,
1020 creds,
1021 database,
1022 delta);
1023 break;
1025 case NETR_DELTA_ALIAS_MEMBER:
1027 nt_status = samsync_ldb_handle_alias_member(mem_ctx,
1028 state,
1029 creds,
1030 database,
1031 delta);
1032 break;
1034 case NETR_DELTA_ACCOUNT:
1036 nt_status = samsync_ldb_handle_account(mem_ctx,
1037 state,
1038 creds,
1039 database,
1040 delta);
1041 break;
1043 case NETR_DELTA_DELETE_ACCOUNT:
1045 nt_status = samsync_ldb_delete_account(mem_ctx,
1046 state,
1047 creds,
1048 database,
1049 delta);
1050 break;
1052 default:
1053 /* Can't dump them all right now */
1054 break;
1056 return nt_status;
1059 static NTSTATUS libnet_samsync_ldb_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1061 NTSTATUS nt_status;
1062 struct libnet_SamSync r2;
1063 struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
1065 if (!state) {
1066 return NT_STATUS_NO_MEMORY;
1069 state->secrets = NULL;
1070 state->trusted_domains = NULL;
1072 state->sam_ldb = samdb_connect(state);
1076 r2.error_string = NULL;
1077 r2.delta_fn = libnet_samsync_ldb_fn;
1078 r2.fn_ctx = state;
1079 r2.machine_account = NULL; /* TODO: Create a machine account, fill this in, and the delete it */
1080 nt_status = libnet_SamSync_netlogon(ctx, state, &r2);
1081 r->error_string = r2.error_string;
1083 if (!NT_STATUS_IS_OK(nt_status)) {
1084 talloc_free(state);
1085 return nt_status;
1087 talloc_free(state);
1088 return nt_status;
1093 static NTSTATUS libnet_samsync_ldb_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1095 NTSTATUS nt_status;
1096 struct libnet_samsync_ldb r2;
1097 r2.level = LIBNET_SAMSYNC_LDB_NETLOGON;
1098 r2.error_string = NULL;
1099 nt_status = libnet_samsync_ldb(ctx, mem_ctx, &r2);
1100 r->error_string = r2.error_string;
1102 return nt_status;
1105 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1107 switch (r->level) {
1108 case LIBNET_SAMSYNC_LDB_GENERIC:
1109 return libnet_samsync_ldb_generic(ctx, mem_ctx, r);
1110 case LIBNET_SAMSYNC_LDB_NETLOGON:
1111 return libnet_samsync_ldb_netlogon(ctx, mem_ctx, r);
1114 return NT_STATUS_INVALID_LEVEL;