s3:wscript_build - add dependency on "tdb-wrap3" for libnet dssync
[Samba.git] / source3 / libnet / libnet_dssync_passdb.c
blob99a7b8019b04f51f018dca119ea78971d3eb4421
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Guenther Deschner <gd@samba.org> 2008
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "system/passwd.h"
22 #include "libnet/libnet_dssync.h"
23 #include "../libcli/security/security.h"
24 #include "../libds/common/flags.h"
25 #include "../librpc/gen_ndr/ndr_drsuapi.h"
26 #include "util_tdb.h"
27 #include "dbwrap/dbwrap.h"
28 #include "../libds/common/flag_mapping.h"
29 #include "passdb.h"
31 /****************************************************************
32 ****************************************************************/
34 struct dssync_passdb {
35 struct pdb_methods *methods;
36 struct db_context *all;
37 struct db_context *aliases;
38 struct db_context *groups;
41 struct dssync_passdb_obj {
42 struct dssync_passdb_obj *self;
43 uint32_t type;
44 struct drsuapi_DsReplicaObjectListItemEx *cur;
45 TDB_DATA key;
46 TDB_DATA data;
47 struct db_context *members;
50 struct dssync_passdb_mem {
51 struct dssync_passdb_mem *self;
52 bool active;
53 struct drsuapi_DsReplicaObjectIdentifier3 *cur;
54 struct dssync_passdb_obj *obj;
55 TDB_DATA key;
56 TDB_DATA data;
59 static NTSTATUS dssync_insert_obj(struct dssync_passdb *pctx,
60 struct db_context *db,
61 struct dssync_passdb_obj *obj)
63 NTSTATUS status;
64 struct db_record *rec;
66 rec = db->fetch_locked(db, talloc_tos(), obj->key);
67 if (rec == NULL) {
68 return NT_STATUS_NO_MEMORY;
70 if (rec->value.dsize != 0) {
71 abort();
74 status = rec->store(rec, obj->data, TDB_INSERT);
75 if (!NT_STATUS_IS_OK(status)) {
76 TALLOC_FREE(rec);
77 return status;
79 TALLOC_FREE(rec);
80 return NT_STATUS_OK;
83 static struct dssync_passdb_obj *dssync_parse_obj(const TDB_DATA data)
85 struct dssync_passdb_obj *obj;
87 if (data.dsize != sizeof(obj)) {
88 return NULL;
92 * we need to copy the pointer to avoid alignment problems
93 * on some systems.
95 memcpy(&obj, data.dptr, sizeof(obj));
97 return talloc_get_type_abort(obj, struct dssync_passdb_obj);
100 static struct dssync_passdb_obj *dssync_search_obj_by_guid(struct dssync_passdb *pctx,
101 struct db_context *db,
102 const struct GUID *guid)
104 struct dssync_passdb_obj *obj;
105 int ret;
106 TDB_DATA key;
107 TDB_DATA data;
109 key = make_tdb_data((const uint8_t *)(const void *)guid,
110 sizeof(*guid));
112 ret = db->fetch(db, talloc_tos(), key, &data);
113 if (ret != 0) {
114 return NULL;
117 obj = dssync_parse_obj(data);
118 return obj;
121 static NTSTATUS dssync_create_obj(struct dssync_passdb *pctx,
122 struct db_context *db,
123 uint32_t type,
124 struct drsuapi_DsReplicaObjectListItemEx *cur,
125 struct dssync_passdb_obj **_obj)
127 NTSTATUS status;
128 struct dssync_passdb_obj *obj;
130 obj = talloc_zero(pctx, struct dssync_passdb_obj);
131 if (obj == NULL) {
132 return NT_STATUS_NO_MEMORY;
134 obj->self = obj;
135 obj->cur = cur;
136 obj->type = type;
137 obj->key = make_tdb_data((const uint8_t *)(void *)&cur->object.identifier->guid,
138 sizeof(cur->object.identifier->guid));
139 obj->data = make_tdb_data((const uint8_t *)(void *)&obj->self,
140 sizeof(obj->self));
142 obj->members = db_open_rbt(obj);
143 if (obj->members == NULL) {
144 return NT_STATUS_NO_MEMORY;
147 status = dssync_insert_obj(pctx, db, obj);
148 if (!NT_STATUS_IS_OK(status)) {
149 TALLOC_FREE(obj);
150 return status;
152 *_obj = obj;
153 return NT_STATUS_OK;
156 static NTSTATUS dssync_insert_mem(struct dssync_passdb *pctx,
157 struct dssync_passdb_obj *obj,
158 struct dssync_passdb_mem *mem)
160 NTSTATUS status;
161 struct db_record *rec;
163 rec = obj->members->fetch_locked(obj->members, talloc_tos(), mem->key);
164 if (rec == NULL) {
165 return NT_STATUS_NO_MEMORY;
167 if (rec->value.dsize != 0) {
168 abort();
171 status = rec->store(rec, mem->data, TDB_INSERT);
172 if (!NT_STATUS_IS_OK(status)) {
173 TALLOC_FREE(rec);
174 return status;
176 TALLOC_FREE(rec);
177 return NT_STATUS_OK;
180 static NTSTATUS dssync_create_mem(struct dssync_passdb *pctx,
181 struct dssync_passdb_obj *obj,
182 bool active,
183 struct drsuapi_DsReplicaObjectIdentifier3 *cur,
184 struct dssync_passdb_mem **_mem)
186 NTSTATUS status;
187 struct dssync_passdb_mem *mem;
189 mem = talloc_zero(pctx, struct dssync_passdb_mem);
190 if (mem == NULL) {
191 return NT_STATUS_NO_MEMORY;
193 mem->self = mem;
194 mem->cur = cur;
195 mem->active = active;
196 mem->obj = NULL;
197 mem->key = make_tdb_data((const uint8_t *)(void *)&cur->guid,
198 sizeof(cur->guid));
199 mem->data = make_tdb_data((const uint8_t *)(void *)&mem->self,
200 sizeof(mem->self));
202 status = dssync_insert_mem(pctx, obj, mem);
203 if (!NT_STATUS_IS_OK(status)) {
204 TALLOC_FREE(obj);
205 return status;
207 *_mem = mem;
208 return NT_STATUS_OK;
211 static struct dssync_passdb_mem *dssync_parse_mem(const TDB_DATA data)
213 struct dssync_passdb_mem *mem;
215 if (data.dsize != sizeof(mem)) {
216 return NULL;
220 * we need to copy the pointer to avoid alignment problems
221 * on some systems.
223 memcpy(&mem, data.dptr, sizeof(mem));
225 return talloc_get_type_abort(mem, struct dssync_passdb_mem);
228 static NTSTATUS passdb_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
229 struct replUpToDateVectorBlob **pold_utdv)
231 NTSTATUS status;
232 struct dssync_passdb *pctx;
234 pctx = talloc_zero(mem_ctx, struct dssync_passdb);
235 if (pctx == NULL) {
236 return NT_STATUS_NO_MEMORY;
239 if (ctx->output_filename) {
240 status = make_pdb_method_name(&pctx->methods, ctx->output_filename);
241 } else {
242 status = make_pdb_method_name(&pctx->methods, lp_passdb_backend());
245 if (!NT_STATUS_IS_OK(status)) {
246 return status;
249 pctx->all = db_open_rbt(pctx);
250 if (pctx->all == NULL) {
251 return NT_STATUS_NO_MEMORY;
253 pctx->aliases = db_open_rbt(pctx);
254 if (pctx->aliases == NULL) {
255 return NT_STATUS_NO_MEMORY;
257 pctx->groups = db_open_rbt(pctx);
258 if (pctx->groups == NULL) {
259 return NT_STATUS_NO_MEMORY;
262 ctx->private_data = pctx;
264 return status;
267 /****************************************************************
268 ****************************************************************/
270 struct dssync_passdb_traverse_amembers {
271 struct dssync_context *ctx;
272 struct dssync_passdb_obj *obj;
273 const char *name;
274 uint32_t idx;
277 struct dssync_passdb_traverse_aliases {
278 struct dssync_context *ctx;
279 const char *name;
280 uint32_t idx;
283 static int dssync_passdb_traverse_amembers(struct db_record *rec,
284 void *private_data)
286 struct dssync_passdb_traverse_amembers *state =
287 (struct dssync_passdb_traverse_amembers *)private_data;
288 struct dssync_passdb *pctx =
289 talloc_get_type_abort(state->ctx->private_data,
290 struct dssync_passdb);
291 struct dssync_passdb_mem *mem;
292 NTSTATUS status;
293 struct dom_sid alias_sid;
294 struct dom_sid member_sid;
295 const char *member_dn;
296 size_t num_members;
297 size_t i;
298 struct dom_sid *members;
299 bool is_member = false;
300 const char *action;
302 state->idx++;
304 alias_sid = state->obj->cur->object.identifier->sid;
306 mem = dssync_parse_mem(rec->value);
307 if (mem == NULL) {
308 return -1;
311 member_sid = mem->cur->sid;
312 member_dn = mem->cur->dn;
314 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
315 if (mem->obj == NULL) {
316 DEBUG(0,("alias[%s] member[%s] can't resolve member - ignoring\n",
317 sid_string_dbg(&alias_sid),
318 is_null_sid(&member_sid)?
319 sid_string_dbg(&member_sid):
320 member_dn));
321 return 0;
324 switch (mem->obj->type) {
325 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
326 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
327 DEBUG(0, ("alias[%s] ignore distribution group [%s]\n",
328 sid_string_dbg(&alias_sid),
329 member_dn));
330 return 0;
331 default:
332 break;
335 DEBUG(0,("alias[%s] member[%s]\n",
336 sid_string_dbg(&alias_sid),
337 sid_string_dbg(&member_sid)));
339 status = pdb_enum_aliasmem(&alias_sid, talloc_tos(),
340 &members, &num_members);
341 if (!NT_STATUS_IS_OK(status)) {
342 DEBUG(0, ("Could not find current alias members %s - %s\n",
343 sid_string_dbg(&alias_sid),
344 nt_errstr(status)));
345 return -1;
348 for (i=0; i < num_members; i++) {
349 bool match;
351 match = dom_sid_equal(&members[i], &member_sid);
352 if (match) {
353 is_member = true;
354 break;
358 status = NT_STATUS_OK;
359 action = "none";
360 if (!is_member && mem->active) {
361 action = "add";
362 pdb_add_aliasmem(&alias_sid, &member_sid);
363 } else if (is_member && !mem->active) {
364 action = "delete";
365 pdb_del_aliasmem(&alias_sid, &member_sid);
367 if (!NT_STATUS_IS_OK(status)) {
368 DEBUG(0, ("Could not %s %s as alias members of %s - %s\n",
369 action,
370 sid_string_dbg(&member_sid),
371 sid_string_dbg(&alias_sid),
372 nt_errstr(status)));
373 return -1;
376 return 0;
379 static int dssync_passdb_traverse_aliases(struct db_record *rec,
380 void *private_data)
382 struct dssync_passdb_traverse_aliases *state =
383 (struct dssync_passdb_traverse_aliases *)private_data;
384 struct dssync_passdb *pctx =
385 talloc_get_type_abort(state->ctx->private_data,
386 struct dssync_passdb);
387 struct dssync_passdb_traverse_amembers mstate;
388 struct dssync_passdb_obj *obj;
389 int ret;
391 state->idx++;
392 if (pctx->methods == NULL) {
393 return -1;
396 obj = dssync_parse_obj(rec->value);
397 if (obj == NULL) {
398 return -1;
401 ZERO_STRUCT(mstate);
402 mstate.ctx = state->ctx;
403 mstate.name = "members";
404 mstate.obj = obj;
405 ret = obj->members->traverse_read(obj->members,
406 dssync_passdb_traverse_amembers,
407 &mstate);
408 if (ret < 0) {
409 return -1;
412 return 0;
415 struct dssync_passdb_traverse_gmembers {
416 struct dssync_context *ctx;
417 struct dssync_passdb_obj *obj;
418 const char *name;
419 uint32_t idx;
422 struct dssync_passdb_traverse_groups {
423 struct dssync_context *ctx;
424 const char *name;
425 uint32_t idx;
428 static int dssync_passdb_traverse_gmembers(struct db_record *rec,
429 void *private_data)
431 struct dssync_passdb_traverse_gmembers *state =
432 (struct dssync_passdb_traverse_gmembers *)private_data;
433 struct dssync_passdb *pctx =
434 talloc_get_type_abort(state->ctx->private_data,
435 struct dssync_passdb);
436 struct dssync_passdb_mem *mem;
437 NTSTATUS status;
438 char *nt_member = NULL;
439 char **unix_members;
440 struct dom_sid group_sid;
441 struct dom_sid member_sid;
442 struct samu *member = NULL;
443 const char *member_dn = NULL;
444 GROUP_MAP map;
445 struct group *grp;
446 uint32_t rid;
447 bool is_unix_member = false;
449 state->idx++;
451 group_sid = state->obj->cur->object.identifier->sid;
453 status = dom_sid_split_rid(talloc_tos(), &group_sid, NULL, &rid);
454 if (!NT_STATUS_IS_OK(status)) {
455 return -1;
458 mem = dssync_parse_mem(rec->value);
459 if (mem == NULL) {
460 return -1;
463 member_sid = mem->cur->sid;
464 member_dn = mem->cur->dn;
466 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
467 if (mem->obj == NULL) {
468 DEBUG(0,("group[%s] member[%s] can't resolve member - ignoring\n",
469 sid_string_dbg(&group_sid),
470 is_null_sid(&member_sid)?
471 sid_string_dbg(&member_sid):
472 member_dn));
473 return 0;
476 member_sid = mem->obj->cur->object.identifier->sid;
477 member_dn = mem->obj->cur->object.identifier->dn;
479 switch (mem->obj->type) {
480 case ATYPE_SECURITY_LOCAL_GROUP:
481 case ATYPE_SECURITY_GLOBAL_GROUP:
482 DEBUG(0, ("Group[%s] ignore member group [%s]\n",
483 sid_string_dbg(&group_sid),
484 sid_string_dbg(&member_sid)));
485 return 0;
487 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
488 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
489 DEBUG(0, ("Group[%s] ignore distribution group [%s]\n",
490 sid_string_dbg(&group_sid),
491 member_dn));
492 return 0;
493 default:
494 break;
497 if (!get_domain_group_from_sid(group_sid, &map)) {
498 DEBUG(0, ("Could not find global group %s\n",
499 sid_string_dbg(&group_sid)));
500 //return NT_STATUS_NO_SUCH_GROUP;
501 return -1;
504 if (!(grp = getgrgid(map.gid))) {
505 DEBUG(0, ("Could not find unix group %lu\n", (unsigned long)map.gid));
506 //return NT_STATUS_NO_SUCH_GROUP;
507 return -1;
510 DEBUG(0,("Group members of %s: ", grp->gr_name));
512 if ( !(member = samu_new(talloc_tos())) ) {
513 //return NT_STATUS_NO_MEMORY;
514 return -1;
517 if (!pdb_getsampwsid(member, &member_sid)) {
518 DEBUG(1, ("Found bogus group member: (member_sid=%s group=%s)\n",
519 sid_string_tos(&member_sid), grp->gr_name));
520 TALLOC_FREE(member);
521 return -1;
524 if (pdb_get_group_rid(member) == rid) {
525 DEBUGADD(0,("%s(primary),", pdb_get_username(member)));
526 TALLOC_FREE(member);
527 return -1;
530 DEBUGADD(0,("%s,", pdb_get_username(member)));
531 nt_member = talloc_strdup(talloc_tos(), pdb_get_username(member));
532 TALLOC_FREE(member);
534 DEBUGADD(0,("\n"));
536 unix_members = grp->gr_mem;
538 while (*unix_members) {
539 if (strcmp(*unix_members, nt_member) == 0) {
540 is_unix_member = true;
541 break;
543 unix_members += 1;
546 if (!is_unix_member && mem->active) {
547 smb_add_user_group(grp->gr_name, nt_member);
548 } else if (is_unix_member && !mem->active) {
549 smb_delete_user_group(grp->gr_name, nt_member);
552 return 0;
555 static int dssync_passdb_traverse_groups(struct db_record *rec,
556 void *private_data)
558 struct dssync_passdb_traverse_groups *state =
559 (struct dssync_passdb_traverse_groups *)private_data;
560 struct dssync_passdb *pctx =
561 talloc_get_type_abort(state->ctx->private_data,
562 struct dssync_passdb);
563 struct dssync_passdb_traverse_gmembers mstate;
564 struct dssync_passdb_obj *obj;
565 int ret;
567 state->idx++;
568 if (pctx->methods == NULL) {
569 return -1;
572 obj = dssync_parse_obj(rec->value);
573 if (obj == NULL) {
574 return -1;
577 ZERO_STRUCT(mstate);
578 mstate.ctx = state->ctx;
579 mstate.name = "members";
580 mstate.obj = obj;
581 ret = obj->members->traverse_read(obj->members,
582 dssync_passdb_traverse_gmembers,
583 &mstate);
584 if (ret < 0) {
585 return -1;
588 return 0;
591 static NTSTATUS passdb_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
592 struct replUpToDateVectorBlob *new_utdv)
594 struct dssync_passdb *pctx =
595 talloc_get_type_abort(ctx->private_data,
596 struct dssync_passdb);
597 struct dssync_passdb_traverse_aliases astate;
598 struct dssync_passdb_traverse_groups gstate;
599 int ret;
601 ZERO_STRUCT(astate);
602 astate.ctx = ctx;
603 astate.name = "aliases";
604 ret = pctx->aliases->traverse_read(pctx->aliases,
605 dssync_passdb_traverse_aliases,
606 &astate);
607 if (ret < 0) {
608 return NT_STATUS_INTERNAL_ERROR;
611 ZERO_STRUCT(gstate);
612 gstate.ctx = ctx;
613 gstate.name = "groups";
614 ret = pctx->groups->traverse_read(pctx->groups,
615 dssync_passdb_traverse_groups,
616 &gstate);
617 if (ret < 0) {
618 return NT_STATUS_INTERNAL_ERROR;
621 TALLOC_FREE(pctx->methods);
622 TALLOC_FREE(pctx);
624 return NT_STATUS_OK;
627 /****************************************************************
628 ****************************************************************/
630 static NTSTATUS smb_create_user(TALLOC_CTX *mem_ctx,
631 uint32_t acct_flags,
632 const char *account,
633 struct passwd **passwd_p)
635 struct passwd *passwd;
636 char *add_script = NULL;
638 passwd = Get_Pwnam_alloc(mem_ctx, account);
639 if (passwd) {
640 *passwd_p = passwd;
641 return NT_STATUS_OK;
644 /* Create appropriate user */
645 if (acct_flags & ACB_NORMAL) {
646 add_script = talloc_strdup(mem_ctx, lp_adduser_script());
647 } else if ( (acct_flags & ACB_WSTRUST) ||
648 (acct_flags & ACB_SVRTRUST) ||
649 (acct_flags & ACB_DOMTRUST) ) {
650 add_script = talloc_strdup(mem_ctx, lp_addmachine_script());
651 } else {
652 DEBUG(1, ("Unknown user type: %s\n",
653 pdb_encode_acct_ctrl(acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN)));
654 return NT_STATUS_UNSUCCESSFUL;
657 if (!add_script) {
658 return NT_STATUS_NO_MEMORY;
661 if (*add_script) {
662 int add_ret;
663 add_script = talloc_all_string_sub(mem_ctx, add_script,
664 "%u", account);
665 if (!add_script) {
666 return NT_STATUS_NO_MEMORY;
668 add_ret = smbrun(add_script, NULL);
669 DEBUG(add_ret ? 0 : 1,("fetch_account: Running the command `%s' "
670 "gave %d\n", add_script, add_ret));
671 if (add_ret == 0) {
672 smb_nscd_flush_user_cache();
676 /* try and find the possible unix account again */
677 passwd = Get_Pwnam_alloc(mem_ctx, account);
678 if (!passwd) {
679 return NT_STATUS_NO_SUCH_USER;
682 *passwd_p = passwd;
684 return NT_STATUS_OK;
687 static struct drsuapi_DsReplicaAttribute *find_drsuapi_attr(
688 const struct drsuapi_DsReplicaObjectListItemEx *cur,
689 uint32_t attid)
691 int i = 0;
693 for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
694 struct drsuapi_DsReplicaAttribute *attr;
696 attr = &cur->object.attribute_ctr.attributes[i];
698 if (attr->attid == attid) {
699 return attr;
703 return NULL;
706 static NTSTATUS find_drsuapi_attr_string(TALLOC_CTX *mem_ctx,
707 const struct drsuapi_DsReplicaObjectListItemEx *cur,
708 uint32_t attid,
709 uint32_t *_count,
710 char ***_array)
712 struct drsuapi_DsReplicaAttribute *attr;
713 char **array;
714 uint32_t a;
716 attr = find_drsuapi_attr(cur, attid);
717 if (attr == NULL) {
718 return NT_STATUS_PROPSET_NOT_FOUND;
721 array = talloc_array(mem_ctx, char *, attr->value_ctr.num_values);
722 if (array == NULL) {
723 return NT_STATUS_NO_MEMORY;
726 for (a = 0; a < attr->value_ctr.num_values; a++) {
727 const DATA_BLOB *blob;
728 ssize_t ret;
730 blob = attr->value_ctr.values[a].blob;
732 if (blob == NULL) {
733 return NT_STATUS_INTERNAL_DB_CORRUPTION;
736 ret = pull_string_talloc(array, NULL, 0, &array[a],
737 blob->data, blob->length,
738 STR_UNICODE);
739 if (ret == -1) {
740 //TODO
741 return NT_STATUS_INTERNAL_ERROR;
745 *_count = attr->value_ctr.num_values;
746 *_array = array;
747 return NT_STATUS_OK;
750 static NTSTATUS find_drsuapi_attr_int32(TALLOC_CTX *mem_ctx,
751 const struct drsuapi_DsReplicaObjectListItemEx *cur,
752 uint32_t attid,
753 uint32_t *_count,
754 int32_t **_array)
756 struct drsuapi_DsReplicaAttribute *attr;
757 int32_t *array;
758 uint32_t a;
760 attr = find_drsuapi_attr(cur, attid);
761 if (attr == NULL) {
762 return NT_STATUS_PROPSET_NOT_FOUND;
765 array = talloc_array(mem_ctx, int32_t, attr->value_ctr.num_values);
766 if (array == NULL) {
767 return NT_STATUS_NO_MEMORY;
770 for (a = 0; a < attr->value_ctr.num_values; a++) {
771 const DATA_BLOB *blob;
773 blob = attr->value_ctr.values[a].blob;
775 if (blob == NULL) {
776 return NT_STATUS_INTERNAL_DB_CORRUPTION;
779 if (blob->length != 4) {
780 return NT_STATUS_INTERNAL_DB_CORRUPTION;
783 array[a] = IVAL(blob->data, 0);
786 *_count = attr->value_ctr.num_values;
787 *_array = array;
788 return NT_STATUS_OK;
791 static NTSTATUS find_drsuapi_attr_blob(TALLOC_CTX *mem_ctx,
792 const struct drsuapi_DsReplicaObjectListItemEx *cur,
793 uint32_t attid,
794 uint32_t *_count,
795 DATA_BLOB **_array)
797 struct drsuapi_DsReplicaAttribute *attr;
798 DATA_BLOB *array;
799 uint32_t a;
801 attr = find_drsuapi_attr(cur, attid);
802 if (attr == NULL) {
803 return NT_STATUS_PROPSET_NOT_FOUND;
806 array = talloc_array(mem_ctx, DATA_BLOB, attr->value_ctr.num_values);
807 if (array == NULL) {
808 return NT_STATUS_NO_MEMORY;
811 for (a = 0; a < attr->value_ctr.num_values; a++) {
812 const DATA_BLOB *blob;
814 blob = attr->value_ctr.values[a].blob;
816 if (blob == NULL) {
817 return NT_STATUS_INTERNAL_DB_CORRUPTION;
820 array[a] = data_blob_talloc(array, blob->data, blob->length);
821 if (array[a].length != blob->length) {
822 return NT_STATUS_NO_MEMORY;
825 *_count = attr->value_ctr.num_values;
826 *_array = array;
827 return NT_STATUS_OK;
830 static NTSTATUS find_drsuapi_attr_int64(TALLOC_CTX *mem_ctx,
831 const struct drsuapi_DsReplicaObjectListItemEx *cur,
832 uint32_t attid,
833 uint32_t *_count,
834 int64_t **_array)
836 struct drsuapi_DsReplicaAttribute *attr;
837 int64_t *array;
838 uint32_t a;
840 attr = find_drsuapi_attr(cur, attid);
841 if (attr == NULL) {
842 return NT_STATUS_PROPSET_NOT_FOUND;
845 array = talloc_array(mem_ctx, int64_t, attr->value_ctr.num_values);
846 if (array == NULL) {
847 return NT_STATUS_NO_MEMORY;
850 for (a = 0; a < attr->value_ctr.num_values; a++) {
851 const DATA_BLOB *blob;
853 blob = attr->value_ctr.values[a].blob;
855 if (blob == NULL) {
856 return NT_STATUS_INTERNAL_DB_CORRUPTION;
859 if (blob->length != 8) {
860 return NT_STATUS_INTERNAL_DB_CORRUPTION;
863 array[a] = BVAL(blob->data, 0);
865 *_count = attr->value_ctr.num_values;
866 *_array = array;
867 return NT_STATUS_OK;
870 static NTSTATUS find_drsuapi_attr_dn(TALLOC_CTX *mem_ctx,
871 const struct drsuapi_DsReplicaObjectListItemEx *cur,
872 uint32_t attid,
873 uint32_t *_count,
874 struct drsuapi_DsReplicaObjectIdentifier3 **_array)
876 struct drsuapi_DsReplicaAttribute *attr;
877 struct drsuapi_DsReplicaObjectIdentifier3 *array;
878 uint32_t a;
880 attr = find_drsuapi_attr(cur, attid);
881 if (attr == NULL) {
882 return NT_STATUS_PROPSET_NOT_FOUND;
885 array = talloc_array(mem_ctx,
886 struct drsuapi_DsReplicaObjectIdentifier3,
887 attr->value_ctr.num_values);
888 if (array == NULL) {
889 return NT_STATUS_NO_MEMORY;
892 for (a = 0; a < attr->value_ctr.num_values; a++) {
893 const DATA_BLOB *blob;
894 enum ndr_err_code ndr_err;
895 NTSTATUS status;
897 blob = attr->value_ctr.values[a].blob;
899 if (blob == NULL) {
900 return NT_STATUS_INTERNAL_DB_CORRUPTION;
903 /* windows sometimes sends an extra two pad bytes here */
904 ndr_err = ndr_pull_struct_blob(blob, array, &array[a],
905 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
906 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
907 status = ndr_map_error2ntstatus(ndr_err);
908 return status;
911 *_count = attr->value_ctr.num_values;
912 *_array = array;
913 return NT_STATUS_OK;
916 #define GET_BLOB_EX(attr, needed) do { \
917 NTSTATUS _status; \
918 uint32_t _cnt; \
919 DATA_BLOB *_vals = NULL; \
920 attr = data_blob_null; \
921 _status = find_drsuapi_attr_blob(mem_ctx, cur, \
922 DRSUAPI_ATTID_ ## attr, \
923 &_cnt, &_vals); \
924 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
925 if (!needed) { \
926 _status = NT_STATUS_OK; \
927 _cnt = 0; \
930 if (!NT_STATUS_IS_OK(_status)) { \
931 DEBUG(0,(__location__ "attr[%s] %s\n", \
932 #attr, nt_errstr(_status))); \
933 return _status; \
935 if (_cnt == 0) { \
936 if (needed) { \
937 talloc_free(_vals); \
938 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
939 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
941 } else if (_cnt > 1) { \
942 talloc_free(_vals); \
943 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
944 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
945 } else { \
946 attr = _vals[0]; \
947 (void)talloc_steal(mem_ctx, _vals[0].data); \
949 talloc_free(_vals); \
950 } while(0)
952 #define GET_STRING_EX(attr, needed) do { \
953 NTSTATUS _status; \
954 uint32_t _cnt; \
955 char **_vals = NULL; \
956 attr = NULL; \
957 _status = find_drsuapi_attr_string(mem_ctx, cur, \
958 DRSUAPI_ATTID_ ## attr, \
959 &_cnt, &_vals); \
960 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
961 if (!needed) { \
962 _status = NT_STATUS_OK; \
963 _cnt = 0; \
966 if (!NT_STATUS_IS_OK(_status)) { \
967 DEBUG(0,(__location__ "attr[%s] %s\n", \
968 #attr, nt_errstr(_status))); \
969 return _status; \
971 if (_cnt == 0) { \
972 if (needed) { \
973 talloc_free(_vals); \
974 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
975 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
977 } else if (_cnt > 1) { \
978 talloc_free(_vals); \
979 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
980 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
981 } else { \
982 attr = talloc_move(mem_ctx, &_vals[0]); \
984 talloc_free(_vals); \
985 } while(0)
987 #define GET_UINT32_EX(attr, needed) do { \
988 NTSTATUS _status; \
989 uint32_t _cnt; \
990 int32_t*_vals = NULL; \
991 attr = 0; \
992 _status = find_drsuapi_attr_int32(mem_ctx, cur, \
993 DRSUAPI_ATTID_ ## attr, \
994 &_cnt, &_vals); \
995 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
996 if (!needed) { \
997 _status = NT_STATUS_OK; \
998 _cnt = 0; \
1001 if (!NT_STATUS_IS_OK(_status)) { \
1002 DEBUG(0,(__location__ "attr[%s] %s\n", \
1003 #attr, nt_errstr(_status))); \
1004 return _status; \
1006 if (_cnt == 0) { \
1007 if (needed) { \
1008 talloc_free(_vals); \
1009 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1010 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1012 } else if (_cnt > 1) { \
1013 talloc_free(_vals); \
1014 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1015 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1016 } else { \
1017 attr = (uint32_t)_vals[0]; \
1019 talloc_free(_vals); \
1020 } while(0)
1022 #define GET_UINT64_EX(attr, needed) do { \
1023 NTSTATUS _status; \
1024 uint32_t _cnt; \
1025 int64_t *_vals = NULL; \
1026 attr = 0; \
1027 _status = find_drsuapi_attr_int64(mem_ctx, cur, \
1028 DRSUAPI_ATTID_ ## attr, \
1029 &_cnt, &_vals); \
1030 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1031 if (!needed) { \
1032 _status = NT_STATUS_OK; \
1033 _cnt = 0; \
1036 if (!NT_STATUS_IS_OK(_status)) { \
1037 DEBUG(0,(__location__ "attr[%s] %s\n", \
1038 #attr, nt_errstr(_status))); \
1039 return _status; \
1041 if (_cnt == 0) { \
1042 if (needed) { \
1043 talloc_free(_vals); \
1044 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1045 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1047 } else if (_cnt > 1) { \
1048 talloc_free(_vals); \
1049 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1050 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1051 } else { \
1052 attr = (uint64_t)_vals[0]; \
1054 talloc_free(_vals); \
1055 } while(0)
1057 #define GET_BLOB(attr) GET_BLOB_EX(attr, false)
1058 #define GET_STRING(attr) GET_STRING_EX(attr, false)
1059 #define GET_UINT32(attr) GET_UINT32_EX(attr, false)
1060 #define GET_UINT64(attr) GET_UINT64_EX(attr, false)
1062 /* Convert a struct samu_DELTA to a struct samu. */
1063 #define STRING_CHANGED (old_string && !new_string) ||\
1064 (!old_string && new_string) ||\
1065 (old_string && new_string && (strcmp(old_string, new_string) != 0))
1067 #define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
1068 (!(s1) && (s2)) ||\
1069 ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
1071 /****************************************************************
1072 ****************************************************************/
1074 static NTSTATUS sam_account_from_object(struct samu *account,
1075 struct drsuapi_DsReplicaObjectListItemEx *cur)
1077 TALLOC_CTX *mem_ctx = account;
1078 const char *old_string, *new_string;
1079 time_t unix_time, stored_time;
1080 uchar zero_buf[16];
1081 NTSTATUS status;
1083 NTTIME lastLogon;
1084 NTTIME lastLogoff;
1085 NTTIME pwdLastSet;
1086 NTTIME accountExpires;
1087 const char *sAMAccountName;
1088 const char *displayName;
1089 const char *homeDirectory;
1090 const char *homeDrive;
1091 const char *scriptPath;
1092 const char *profilePath;
1093 const char *description;
1094 const char *userWorkstations;
1095 const char *comment;
1096 DATA_BLOB userParameters;
1097 struct dom_sid objectSid;
1098 uint32_t primaryGroupID;
1099 uint32_t userAccountControl;
1100 DATA_BLOB logonHours;
1101 uint32_t badPwdCount;
1102 uint32_t logonCount;
1103 DATA_BLOB unicodePwd;
1104 DATA_BLOB dBCSPwd;
1106 uint32_t rid = 0;
1107 uint32_t acct_flags;
1108 uint32_t units_per_week;
1110 memset(zero_buf, '\0', sizeof(zero_buf));
1112 objectSid = cur->object.identifier->sid;
1113 GET_STRING_EX(sAMAccountName, true);
1114 DEBUG(0,("sam_account_from_object(%s, %s) start\n",
1115 sAMAccountName, sid_string_dbg(&objectSid)));
1116 GET_UINT64(lastLogon);
1117 GET_UINT64(lastLogoff);
1118 GET_UINT64(pwdLastSet);
1119 GET_UINT64(accountExpires);
1120 GET_STRING(displayName);
1121 GET_STRING(homeDirectory);
1122 GET_STRING(homeDrive);
1123 GET_STRING(scriptPath);
1124 GET_STRING(profilePath);
1125 GET_STRING(description);
1126 GET_STRING(userWorkstations);
1127 GET_STRING(comment);
1128 GET_BLOB(userParameters);
1129 GET_UINT32(primaryGroupID);
1130 GET_UINT32(userAccountControl);
1131 GET_BLOB(logonHours);
1132 GET_UINT32(badPwdCount);
1133 GET_UINT32(logonCount);
1134 GET_BLOB(unicodePwd);
1135 GET_BLOB(dBCSPwd);
1137 status = dom_sid_split_rid(mem_ctx, &objectSid, NULL, &rid);
1138 if (!NT_STATUS_IS_OK(status)) {
1139 return status;
1141 acct_flags = ds_uf2acb(userAccountControl);
1143 /* Username, fullname, home dir, dir drive, logon script, acct
1144 desc, workstations, profile. */
1146 if (sAMAccountName) {
1147 old_string = pdb_get_nt_username(account);
1148 new_string = sAMAccountName;
1150 if (STRING_CHANGED) {
1151 pdb_set_nt_username(account, new_string, PDB_CHANGED);
1154 /* Unix username is the same - for sanity */
1155 old_string = pdb_get_username( account );
1156 if (STRING_CHANGED) {
1157 pdb_set_username(account, new_string, PDB_CHANGED);
1161 if (displayName) {
1162 old_string = pdb_get_fullname(account);
1163 new_string = displayName;
1165 if (STRING_CHANGED)
1166 pdb_set_fullname(account, new_string, PDB_CHANGED);
1169 if (homeDirectory) {
1170 old_string = pdb_get_homedir(account);
1171 new_string = homeDirectory;
1173 if (STRING_CHANGED)
1174 pdb_set_homedir(account, new_string, PDB_CHANGED);
1177 if (homeDrive) {
1178 old_string = pdb_get_dir_drive(account);
1179 new_string = homeDrive;
1181 if (STRING_CHANGED)
1182 pdb_set_dir_drive(account, new_string, PDB_CHANGED);
1185 if (scriptPath) {
1186 old_string = pdb_get_logon_script(account);
1187 new_string = scriptPath;
1189 if (STRING_CHANGED)
1190 pdb_set_logon_script(account, new_string, PDB_CHANGED);
1193 if (description) {
1194 old_string = pdb_get_acct_desc(account);
1195 new_string = description;
1197 if (STRING_CHANGED)
1198 pdb_set_acct_desc(account, new_string, PDB_CHANGED);
1201 if (userWorkstations) {
1202 old_string = pdb_get_workstations(account);
1203 new_string = userWorkstations;
1205 if (STRING_CHANGED)
1206 pdb_set_workstations(account, new_string, PDB_CHANGED);
1209 if (profilePath) {
1210 old_string = pdb_get_profile_path(account);
1211 new_string = profilePath;
1213 if (STRING_CHANGED)
1214 pdb_set_profile_path(account, new_string, PDB_CHANGED);
1217 if (userParameters.data) {
1218 char *newstr;
1219 old_string = pdb_get_munged_dial(account);
1220 newstr = (userParameters.length == 0) ? NULL :
1221 base64_encode_data_blob(talloc_tos(), userParameters);
1223 if (STRING_CHANGED_NC(old_string, newstr))
1224 pdb_set_munged_dial(account, newstr, PDB_CHANGED);
1225 TALLOC_FREE(newstr);
1228 /* User and group sid */
1229 if (rid != 0 && pdb_get_user_rid(account) != rid) {
1230 pdb_set_user_sid_from_rid(account, rid, PDB_CHANGED);
1232 if (primaryGroupID != 0 && pdb_get_group_rid(account) != primaryGroupID) {
1233 pdb_set_group_sid_from_rid(account, primaryGroupID, PDB_CHANGED);
1236 /* Logon and password information */
1237 if (!nt_time_is_zero(&lastLogon)) {
1238 unix_time = nt_time_to_unix(lastLogon);
1239 stored_time = pdb_get_logon_time(account);
1240 if (stored_time != unix_time)
1241 pdb_set_logon_time(account, unix_time, PDB_CHANGED);
1244 if (!nt_time_is_zero(&lastLogoff)) {
1245 unix_time = nt_time_to_unix(lastLogoff);
1246 stored_time = pdb_get_logoff_time(account);
1247 if (stored_time != unix_time)
1248 pdb_set_logoff_time(account, unix_time,PDB_CHANGED);
1251 /* Logon Divs */
1252 units_per_week = logonHours.length * 8;
1254 if (pdb_get_logon_divs(account) != units_per_week) {
1255 pdb_set_logon_divs(account, units_per_week, PDB_CHANGED);
1258 /* Logon Hours Len */
1259 if (units_per_week/8 != pdb_get_hours_len(account)) {
1260 pdb_set_hours_len(account, units_per_week/8, PDB_CHANGED);
1263 /* Logon Hours */
1264 if (logonHours.data) {
1265 char oldstr[44], newstr[44];
1266 pdb_sethexhours(oldstr, pdb_get_hours(account));
1267 pdb_sethexhours(newstr, logonHours.data);
1268 if (!strequal(oldstr, newstr)) {
1269 pdb_set_hours(account, logonHours.data,
1270 logonHours.length, PDB_CHANGED);
1274 if (pdb_get_bad_password_count(account) != badPwdCount)
1275 pdb_set_bad_password_count(account, badPwdCount, PDB_CHANGED);
1277 if (pdb_get_logon_count(account) != logonCount)
1278 pdb_set_logon_count(account, logonCount, PDB_CHANGED);
1280 if (!nt_time_is_zero(&pwdLastSet)) {
1281 unix_time = nt_time_to_unix(pwdLastSet);
1282 stored_time = pdb_get_pass_last_set_time(account);
1283 if (stored_time != unix_time)
1284 pdb_set_pass_last_set_time(account, unix_time, PDB_CHANGED);
1285 } else {
1286 /* no last set time, make it now */
1287 pdb_set_pass_last_set_time(account, time(NULL), PDB_CHANGED);
1290 if (!nt_time_is_zero(&accountExpires)) {
1291 unix_time = nt_time_to_unix(accountExpires);
1292 stored_time = pdb_get_kickoff_time(account);
1293 if (stored_time != unix_time)
1294 pdb_set_kickoff_time(account, unix_time, PDB_CHANGED);
1297 /* Decode hashes from password hash
1298 Note that win2000 may send us all zeros for the hashes if it doesn't
1299 think this channel is secure enough - don't set the passwords at all
1300 in that case
1302 if (dBCSPwd.length == 16 && memcmp(dBCSPwd.data, zero_buf, 16) != 0) {
1303 pdb_set_lanman_passwd(account, dBCSPwd.data, PDB_CHANGED);
1306 if (unicodePwd.length == 16 && memcmp(unicodePwd.data, zero_buf, 16) != 0) {
1307 pdb_set_nt_passwd(account, unicodePwd.data, PDB_CHANGED);
1310 /* TODO: history */
1312 /* TODO: account expiry time */
1314 pdb_set_acct_ctrl(account, acct_flags, PDB_CHANGED);
1316 pdb_set_domain(account, lp_workgroup(), PDB_CHANGED);
1318 DEBUG(0,("sam_account_from_object(%s, %s) done\n",
1319 sAMAccountName, sid_string_dbg(&objectSid)));
1320 return NT_STATUS_OK;
1323 /****************************************************************
1324 ****************************************************************/
1326 static NTSTATUS handle_account_object(struct dssync_passdb *pctx,
1327 TALLOC_CTX *mem_ctx,
1328 struct dssync_passdb_obj *obj)
1330 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1331 NTSTATUS status;
1332 fstring account;
1333 struct samu *sam_account=NULL;
1334 GROUP_MAP map;
1335 struct group *grp;
1336 struct dom_sid user_sid;
1337 struct dom_sid group_sid;
1338 struct passwd *passwd = NULL;
1339 uint32_t acct_flags;
1340 uint32_t rid;
1342 const char *sAMAccountName;
1343 uint32_t sAMAccountType;
1344 uint32_t userAccountControl;
1346 user_sid = cur->object.identifier->sid;
1347 GET_STRING_EX(sAMAccountName, true);
1348 GET_UINT32_EX(sAMAccountType, true);
1349 GET_UINT32_EX(userAccountControl, true);
1351 status = dom_sid_split_rid(mem_ctx, &user_sid, NULL, &rid);
1352 if (!NT_STATUS_IS_OK(status)) {
1353 return status;
1356 fstrcpy(account, sAMAccountName);
1357 if (rid == DOMAIN_RID_GUEST) {
1359 * pdb_getsampwsid() has special handling for DOMAIN_RID_GUEST
1360 * that's why we need to ignore it here.
1362 * pdb_smbpasswd.c also has some DOMAIN_RID_GUEST related
1363 * code...
1365 DEBUG(0,("Ignore %s - %s\n", account, sid_string_dbg(&user_sid)));
1366 return NT_STATUS_OK;
1368 DEBUG(0,("Creating account: %s\n", account));
1370 if ( !(sam_account = samu_new(mem_ctx)) ) {
1371 return NT_STATUS_NO_MEMORY;
1374 acct_flags = ds_uf2acb(userAccountControl);
1375 status = smb_create_user(sam_account, acct_flags, account, &passwd);
1376 if (!NT_STATUS_IS_OK(status)) {
1377 DEBUG(0,("Could not create posix account info for '%s'- %s\n",
1378 account, nt_errstr(status)));
1379 TALLOC_FREE(sam_account);
1380 return status;
1383 DEBUG(3, ("Attempting to find SID %s for user %s in the passdb\n",
1384 sid_string_dbg(&user_sid), account));
1385 if (!pdb_getsampwsid(sam_account, &user_sid)) {
1386 sam_account_from_object(sam_account, cur);
1387 DEBUG(3, ("Attempting to add user SID %s for user %s in the passdb\n",
1388 sid_string_dbg(&user_sid),
1389 pdb_get_username(sam_account)));
1390 if (!NT_STATUS_IS_OK(pdb_add_sam_account(sam_account))) {
1391 DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n",
1392 account));
1393 TALLOC_FREE(sam_account);
1394 return NT_STATUS_ACCESS_DENIED;
1396 } else {
1397 sam_account_from_object(sam_account, cur);
1398 DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n",
1399 sid_string_dbg(&user_sid),
1400 pdb_get_username(sam_account)));
1401 if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) {
1402 DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n",
1403 account));
1404 TALLOC_FREE(sam_account);
1405 return NT_STATUS_ACCESS_DENIED;
1409 if (pdb_get_group_sid(sam_account) == NULL) {
1410 TALLOC_FREE(sam_account);
1411 return NT_STATUS_UNSUCCESSFUL;
1414 group_sid = *pdb_get_group_sid(sam_account);
1416 if (!pdb_getgrsid(&map, group_sid)) {
1417 DEBUG(0, ("Primary group of %s has no mapping!\n",
1418 pdb_get_username(sam_account)));
1419 } else {
1420 if (map.gid != passwd->pw_gid) {
1421 if (!(grp = getgrgid(map.gid))) {
1422 DEBUG(0, ("Could not find unix group %lu for user %s (group SID=%s)\n",
1423 (unsigned long)map.gid, pdb_get_username(sam_account),
1424 sid_string_dbg(&group_sid)));
1425 } else {
1426 smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
1431 if ( !passwd ) {
1432 DEBUG(1, ("No unix user for this account (%s), cannot adjust mappings\n",
1433 pdb_get_username(sam_account)));
1436 TALLOC_FREE(sam_account);
1437 return NT_STATUS_OK;
1440 /****************************************************************
1441 ****************************************************************/
1443 static NTSTATUS handle_alias_object(struct dssync_passdb *pctx,
1444 TALLOC_CTX *mem_ctx,
1445 struct dssync_passdb_obj *obj)
1447 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1448 NTSTATUS status;
1449 fstring name;
1450 fstring comment;
1451 struct group *grp = NULL;
1452 struct dom_sid group_sid;
1453 uint32_t rid = 0;
1454 struct dom_sid *dom_sid = NULL;
1455 fstring sid_string;
1456 GROUP_MAP map;
1457 bool insert = true;
1459 const char *sAMAccountName;
1460 uint32_t sAMAccountType;
1461 uint32_t groupType;
1462 const char *description;
1463 uint32_t i;
1464 uint32_t num_members = 0;
1465 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1467 group_sid = cur->object.identifier->sid;
1468 GET_STRING_EX(sAMAccountName, true);
1469 GET_UINT32_EX(sAMAccountType, true);
1470 GET_UINT32_EX(groupType, true);
1471 GET_STRING(description);
1473 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1474 &num_members, &members);
1475 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1476 status = NT_STATUS_OK;
1478 if (!NT_STATUS_IS_OK(status)) {
1479 return status;
1482 fstrcpy(name, sAMAccountName);
1483 fstrcpy(comment, description);
1485 dom_sid_split_rid(mem_ctx, &group_sid, &dom_sid, &rid);
1487 sid_to_fstring(sid_string, &group_sid);
1488 DEBUG(0,("Creating alias[%s] - %s members[%u]\n",
1489 name, sid_string, num_members));
1491 status = dssync_insert_obj(pctx, pctx->aliases, obj);
1492 if (!NT_STATUS_IS_OK(status)) {
1493 return status;
1496 if (pdb_getgrsid(&map, group_sid)) {
1497 if ( map.gid != -1 )
1498 grp = getgrgid(map.gid);
1499 insert = false;
1502 if (grp == NULL) {
1503 gid_t gid;
1505 /* No group found from mapping, find it from its name. */
1506 if ((grp = getgrnam(name)) == NULL) {
1508 /* No appropriate group found, create one */
1510 DEBUG(0,("Creating unix group: '%s'\n", name));
1512 if (smb_create_group(name, &gid) != 0)
1513 return NT_STATUS_ACCESS_DENIED;
1515 if ((grp = getgrgid(gid)) == NULL)
1516 return NT_STATUS_ACCESS_DENIED;
1520 map.gid = grp->gr_gid;
1521 map.sid = group_sid;
1523 if (dom_sid_equal(dom_sid, &global_sid_Builtin)) {
1525 * pdb_ldap does not like SID_NAME_WKN_GRP...
1527 * map.sid_name_use = SID_NAME_WKN_GRP;
1529 map.sid_name_use = SID_NAME_ALIAS;
1530 } else {
1531 map.sid_name_use = SID_NAME_ALIAS;
1534 strlcpy(map.nt_name, name, sizeof(map.nt_name));
1535 if (description) {
1536 strlcpy(map.comment, comment, sizeof(map.comment));
1537 } else {
1538 strlcpy(map.comment, "", sizeof(map.comment));
1541 if (insert)
1542 pdb_add_group_mapping_entry(&map);
1543 else
1544 pdb_update_group_mapping_entry(&map);
1546 for (i=0; i < num_members; i++) {
1547 struct dssync_passdb_mem *mem;
1549 status = dssync_create_mem(pctx, obj,
1550 true /* active */,
1551 &members[i], &mem);
1552 if (!NT_STATUS_IS_OK(status)) {
1553 return status;
1557 return NT_STATUS_OK;
1560 /****************************************************************
1561 ****************************************************************/
1563 static NTSTATUS handle_group_object(struct dssync_passdb *pctx,
1564 TALLOC_CTX *mem_ctx,
1565 struct dssync_passdb_obj *obj)
1567 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1568 NTSTATUS status;
1569 fstring name;
1570 fstring comment;
1571 struct group *grp = NULL;
1572 struct dom_sid group_sid;
1573 fstring sid_string;
1574 GROUP_MAP map;
1575 bool insert = true;
1577 const char *sAMAccountName;
1578 uint32_t sAMAccountType;
1579 uint32_t groupType;
1580 const char *description;
1581 uint32_t i;
1582 uint32_t num_members = 0;
1583 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1585 group_sid = cur->object.identifier->sid;
1586 GET_STRING_EX(sAMAccountName, true);
1587 GET_UINT32_EX(sAMAccountType, true);
1588 GET_UINT32_EX(groupType, true);
1589 GET_STRING(description);
1591 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1592 &num_members, &members);
1593 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1594 status = NT_STATUS_OK;
1596 if (!NT_STATUS_IS_OK(status)) {
1597 return status;
1600 fstrcpy(name, sAMAccountName);
1601 fstrcpy(comment, description);
1603 sid_to_fstring(sid_string, &group_sid);
1604 DEBUG(0,("Creating group[%s] - %s members [%u]\n",
1605 name, sid_string, num_members));
1607 status = dssync_insert_obj(pctx, pctx->groups, obj);
1608 if (!NT_STATUS_IS_OK(status)) {
1609 return status;
1612 if (pdb_getgrsid(&map, group_sid)) {
1613 if ( map.gid != -1 )
1614 grp = getgrgid(map.gid);
1615 insert = false;
1618 if (grp == NULL) {
1619 gid_t gid;
1621 /* No group found from mapping, find it from its name. */
1622 if ((grp = getgrnam(name)) == NULL) {
1624 /* No appropriate group found, create one */
1626 DEBUG(0,("Creating unix group: '%s'\n", name));
1628 if (smb_create_group(name, &gid) != 0)
1629 return NT_STATUS_ACCESS_DENIED;
1631 if ((grp = getgrnam(name)) == NULL)
1632 return NT_STATUS_ACCESS_DENIED;
1636 map.gid = grp->gr_gid;
1637 map.sid = group_sid;
1638 map.sid_name_use = SID_NAME_DOM_GRP;
1639 strlcpy(map.nt_name, name, sizeof(map.nt_name));
1640 if (description) {
1641 strlcpy(map.comment, comment, sizeof(map.comment));
1642 } else {
1643 strlcpy(map.comment, "", sizeof(map.comment));
1646 if (insert)
1647 pdb_add_group_mapping_entry(&map);
1648 else
1649 pdb_update_group_mapping_entry(&map);
1651 for (i=0; i < num_members; i++) {
1652 struct dssync_passdb_mem *mem;
1654 status = dssync_create_mem(pctx, obj,
1655 true /* active */,
1656 &members[i], &mem);
1657 if (!NT_STATUS_IS_OK(status)) {
1658 return status;
1662 return NT_STATUS_OK;
1665 /****************************************************************
1666 ****************************************************************/
1668 static NTSTATUS handle_interdomain_trust_object(struct dssync_passdb *pctx,
1669 TALLOC_CTX *mem_ctx,
1670 struct dssync_passdb_obj *obj)
1672 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1673 DEBUG(0,("trust: %s\n", cur->object.identifier->dn));
1674 return NT_STATUS_NOT_IMPLEMENTED;
1677 /****************************************************************
1678 ****************************************************************/
1680 struct dssync_object_table_t {
1681 uint32_t type;
1682 NTSTATUS (*fn) (struct dssync_passdb *pctx,
1683 TALLOC_CTX *mem_ctx,
1684 struct dssync_passdb_obj *obj);
1687 static const struct dssync_object_table_t dssync_object_table[] = {
1688 { ATYPE_NORMAL_ACCOUNT, handle_account_object },
1689 { ATYPE_WORKSTATION_TRUST, handle_account_object },
1690 { ATYPE_SECURITY_LOCAL_GROUP, handle_alias_object },
1691 { ATYPE_SECURITY_GLOBAL_GROUP, handle_group_object },
1692 { ATYPE_INTERDOMAIN_TRUST, handle_interdomain_trust_object },
1695 /****************************************************************
1696 ****************************************************************/
1698 static NTSTATUS parse_object(struct dssync_passdb *pctx,
1699 TALLOC_CTX *mem_ctx,
1700 struct drsuapi_DsReplicaObjectListItemEx *cur)
1702 NTSTATUS status = NT_STATUS_OK;
1703 DATA_BLOB *blob;
1704 int i = 0;
1705 int a = 0;
1706 struct drsuapi_DsReplicaAttribute *attr;
1708 char *name = NULL;
1709 uint32_t uacc = 0;
1710 uint32_t sam_type = 0;
1712 DEBUG(3, ("parsing object '%s'\n", cur->object.identifier->dn));
1714 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
1716 attr = &cur->object.attribute_ctr.attributes[i];
1718 if (attr->value_ctr.num_values != 1) {
1719 continue;
1722 if (!attr->value_ctr.values[0].blob) {
1723 continue;
1726 blob = attr->value_ctr.values[0].blob;
1728 switch (attr->attid) {
1729 case DRSUAPI_ATTID_sAMAccountName:
1730 pull_string_talloc(mem_ctx, NULL, 0, &name,
1731 blob->data, blob->length,
1732 STR_UNICODE);
1733 break;
1734 case DRSUAPI_ATTID_sAMAccountType:
1735 sam_type = IVAL(blob->data, 0);
1736 break;
1737 case DRSUAPI_ATTID_userAccountControl:
1738 uacc = IVAL(blob->data, 0);
1739 break;
1740 default:
1741 break;
1745 for (a=0; a < ARRAY_SIZE(dssync_object_table); a++) {
1746 if (sam_type == dssync_object_table[a].type) {
1747 if (dssync_object_table[a].fn) {
1748 struct dssync_passdb_obj *obj;
1749 status = dssync_create_obj(pctx, pctx->all,
1750 sam_type, cur, &obj);
1751 if (!NT_STATUS_IS_OK(status)) {
1752 break;
1754 status = dssync_object_table[a].fn(pctx,
1755 mem_ctx,
1756 obj);
1757 break;
1762 return status;
1765 static NTSTATUS parse_link(struct dssync_passdb *pctx,
1766 TALLOC_CTX *mem_ctx,
1767 struct drsuapi_DsReplicaLinkedAttribute *cur)
1769 struct drsuapi_DsReplicaObjectIdentifier3 *id3;
1770 const DATA_BLOB *blob;
1771 enum ndr_err_code ndr_err;
1772 NTSTATUS status;
1773 bool active = false;
1774 struct dssync_passdb_mem *mem;
1775 struct dssync_passdb_obj *obj;
1777 if (cur->attid != DRSUAPI_ATTID_member) {
1778 return NT_STATUS_OK;
1781 if (cur->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
1782 active = true;
1785 DEBUG(3, ("parsing link '%s' - %s\n",
1786 cur->identifier->dn, active?"adding":"deleting"));
1788 blob = cur->value.blob;
1790 if (blob == NULL) {
1791 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1794 obj = dssync_search_obj_by_guid(pctx, pctx->all, &cur->identifier->guid);
1795 if (obj == NULL) {
1796 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1799 id3 = talloc_zero(obj, struct drsuapi_DsReplicaObjectIdentifier3);
1800 if (id3 == NULL) {
1801 return NT_STATUS_NO_MEMORY;
1804 /* windows sometimes sends an extra two pad bytes here */
1805 ndr_err = ndr_pull_struct_blob(blob, id3, id3,
1806 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
1807 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1808 status = ndr_map_error2ntstatus(ndr_err);
1809 return status;
1812 status = dssync_create_mem(pctx, obj,
1813 active,
1814 id3, &mem);
1815 if (!NT_STATUS_IS_OK(status)) {
1816 return status;
1819 return NT_STATUS_OK;
1822 /****************************************************************
1823 ****************************************************************/
1825 static NTSTATUS passdb_process_objects(struct dssync_context *ctx,
1826 TALLOC_CTX *mem_ctx,
1827 struct drsuapi_DsReplicaObjectListItemEx *cur,
1828 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1830 NTSTATUS status = NT_STATUS_OK;
1831 struct dssync_passdb *pctx =
1832 talloc_get_type_abort(ctx->private_data,
1833 struct dssync_passdb);
1835 for (; cur; cur = cur->next_object) {
1836 status = parse_object(pctx, mem_ctx, cur);
1837 if (!NT_STATUS_IS_OK(status)) {
1838 goto out;
1842 out:
1843 return status;
1846 /****************************************************************
1847 ****************************************************************/
1849 static NTSTATUS passdb_process_links(struct dssync_context *ctx,
1850 TALLOC_CTX *mem_ctx,
1851 uint32_t count,
1852 struct drsuapi_DsReplicaLinkedAttribute *links,
1853 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1855 NTSTATUS status = NT_STATUS_OK;
1856 struct dssync_passdb *pctx =
1857 talloc_get_type_abort(ctx->private_data,
1858 struct dssync_passdb);
1859 uint32_t i;
1861 for (i = 0; i < count; i++) {
1862 status = parse_link(pctx, mem_ctx, &links[i]);
1863 if (!NT_STATUS_IS_OK(status)) {
1864 goto out;
1868 out:
1869 return status;
1872 /****************************************************************
1873 ****************************************************************/
1875 const struct dssync_ops libnet_dssync_passdb_ops = {
1876 .startup = passdb_startup,
1877 .process_objects = passdb_process_objects,
1878 .process_links = passdb_process_links,
1879 .finish = passdb_finish,