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/>.
21 #include "libnet/libnet_dssync.h"
22 #include "libnet/libnet_samsync.h"
23 #include "../libcli/security/security.h"
24 #include "../libds/common/flags.h"
25 #include "../librpc/gen_ndr/ndr_drsuapi.h"
28 /****************************************************************
29 ****************************************************************/
31 struct dssync_passdb {
32 struct pdb_methods *methods;
33 struct db_context *all;
34 struct db_context *aliases;
35 struct db_context *groups;
38 struct dssync_passdb_obj {
39 struct dssync_passdb_obj *self;
41 struct drsuapi_DsReplicaObjectListItemEx *cur;
44 struct db_context *members;
47 struct dssync_passdb_mem {
48 struct dssync_passdb_mem *self;
50 struct drsuapi_DsReplicaObjectIdentifier3 *cur;
51 struct dssync_passdb_obj *obj;
56 static NTSTATUS dssync_insert_obj(struct dssync_passdb *pctx,
57 struct db_context *db,
58 struct dssync_passdb_obj *obj)
61 struct db_record *rec;
63 rec = db->fetch_locked(db, talloc_tos(), obj->key);
65 return NT_STATUS_NO_MEMORY;
67 if (rec->value.dsize != 0) {
71 status = rec->store(rec, obj->data, TDB_INSERT);
72 if (!NT_STATUS_IS_OK(status)) {
80 static struct dssync_passdb_obj *dssync_parse_obj(const TDB_DATA data)
82 struct dssync_passdb_obj *obj;
84 if (data.dsize != sizeof(obj)) {
89 * we need to copy the pointer to avoid alignment problems
92 memcpy(&obj, data.dptr, sizeof(obj));
94 return talloc_get_type_abort(obj, struct dssync_passdb_obj);
97 static struct dssync_passdb_obj *dssync_search_obj_by_guid(struct dssync_passdb *pctx,
98 struct db_context *db,
99 const struct GUID *guid)
101 struct dssync_passdb_obj *obj;
106 key = make_tdb_data((const uint8_t *)(void *)guid,
109 ret = db->fetch(db, talloc_tos(), key, &data);
114 obj = dssync_parse_obj(data);
118 static NTSTATUS dssync_create_obj(struct dssync_passdb *pctx,
119 struct db_context *db,
121 struct drsuapi_DsReplicaObjectListItemEx *cur,
122 struct dssync_passdb_obj **_obj)
125 struct dssync_passdb_obj *obj;
127 obj = talloc_zero(pctx, struct dssync_passdb_obj);
129 return NT_STATUS_NO_MEMORY;
134 obj->key = make_tdb_data((const uint8_t *)(void *)&cur->object.identifier->guid,
135 sizeof(cur->object.identifier->guid));
136 obj->data = make_tdb_data((const uint8_t *)(void *)&obj->self,
139 obj->members = db_open_rbt(obj);
140 if (obj->members == NULL) {
141 return NT_STATUS_NO_MEMORY;
144 status = dssync_insert_obj(pctx, db, obj);
145 if (!NT_STATUS_IS_OK(status)) {
153 static NTSTATUS dssync_insert_mem(struct dssync_passdb *pctx,
154 struct dssync_passdb_obj *obj,
155 struct dssync_passdb_mem *mem)
158 struct db_record *rec;
160 rec = obj->members->fetch_locked(obj->members, talloc_tos(), mem->key);
162 return NT_STATUS_NO_MEMORY;
164 if (rec->value.dsize != 0) {
168 status = rec->store(rec, mem->data, TDB_INSERT);
169 if (!NT_STATUS_IS_OK(status)) {
177 static NTSTATUS dssync_create_mem(struct dssync_passdb *pctx,
178 struct dssync_passdb_obj *obj,
180 struct drsuapi_DsReplicaObjectIdentifier3 *cur,
181 struct dssync_passdb_mem **_mem)
184 struct dssync_passdb_mem *mem;
186 mem = talloc_zero(pctx, struct dssync_passdb_mem);
188 return NT_STATUS_NO_MEMORY;
192 mem->active = active;
194 mem->key = make_tdb_data((const uint8_t *)(void *)&cur->guid,
196 mem->data = make_tdb_data((const uint8_t *)(void *)&mem->self,
199 status = dssync_insert_mem(pctx, obj, mem);
200 if (!NT_STATUS_IS_OK(status)) {
208 static struct dssync_passdb_mem *dssync_parse_mem(const TDB_DATA data)
210 struct dssync_passdb_mem *mem;
212 if (data.dsize != sizeof(mem)) {
217 * we need to copy the pointer to avoid alignment problems
220 memcpy(&mem, data.dptr, sizeof(mem));
222 return talloc_get_type_abort(mem, struct dssync_passdb_mem);
225 static NTSTATUS passdb_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
226 struct replUpToDateVectorBlob **pold_utdv)
229 struct dssync_passdb *pctx;
231 pctx = talloc_zero(mem_ctx, struct dssync_passdb);
233 return NT_STATUS_NO_MEMORY;
236 if (ctx->output_filename) {
237 status = make_pdb_method_name(&pctx->methods, ctx->output_filename);
239 status = make_pdb_method_name(&pctx->methods, lp_passdb_backend());
242 if (!NT_STATUS_IS_OK(status)) {
246 pctx->all = db_open_rbt(pctx);
247 if (pctx->all == NULL) {
248 return NT_STATUS_NO_MEMORY;
250 pctx->aliases = db_open_rbt(pctx);
251 if (pctx->aliases == NULL) {
252 return NT_STATUS_NO_MEMORY;
254 pctx->groups = db_open_rbt(pctx);
255 if (pctx->groups == NULL) {
256 return NT_STATUS_NO_MEMORY;
259 ctx->private_data = pctx;
264 /****************************************************************
265 ****************************************************************/
267 struct dssync_passdb_traverse_amembers {
268 struct dssync_context *ctx;
269 struct dssync_passdb_obj *obj;
274 struct dssync_passdb_traverse_aliases {
275 struct dssync_context *ctx;
280 static int dssync_passdb_traverse_amembers(struct db_record *rec,
283 struct dssync_passdb_traverse_amembers *state =
284 (struct dssync_passdb_traverse_amembers *)private_data;
285 struct dssync_passdb *pctx =
286 talloc_get_type_abort(state->ctx->private_data,
287 struct dssync_passdb);
288 struct dssync_passdb_mem *mem;
290 struct dom_sid alias_sid;
291 struct dom_sid member_sid;
292 const char *member_dn;
295 struct dom_sid *members;
296 bool is_member = false;
301 DEBUG(0,("%s[%u]...\n", state->name, state->idx));
303 alias_sid = state->obj->cur->object.identifier->sid;
305 mem = dssync_parse_mem(rec->value);
310 member_sid = mem->cur->sid;
311 member_dn = mem->cur->dn;
313 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
314 if (mem->obj == NULL) {
315 DEBUG(0,("alias[%s] member[%s] can't resolve member - ignoring\n",
316 sid_string_dbg(&alias_sid),
317 is_null_sid(&member_sid)?
318 sid_string_dbg(&member_sid):
323 switch (mem->obj->type) {
324 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
325 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
326 DEBUG(0, ("alias[%s] ignore distribution group [%s]\n",
327 sid_string_dbg(&alias_sid),
334 DEBUG(0,("alias[%s] member[%s]\n",
335 sid_string_dbg(&alias_sid),
336 sid_string_dbg(&member_sid)));
338 status = pdb_enum_aliasmem(&alias_sid, talloc_tos(),
339 &members, &num_members);
340 if (!NT_STATUS_IS_OK(status)) {
341 DEBUG(0, ("Could not find current alias members %s - %s\n",
342 sid_string_dbg(&alias_sid),
347 for (i=0; i < num_members; i++) {
350 match = dom_sid_equal(&members[i], &member_sid);
357 status = NT_STATUS_OK;
359 if (!is_member && mem->active) {
361 pdb_add_aliasmem(&alias_sid, &member_sid);
362 } else if (is_member && !mem->active) {
364 pdb_del_aliasmem(&alias_sid, &member_sid);
366 if (!NT_STATUS_IS_OK(status)) {
367 DEBUG(0, ("Could not %s %s as alias members of %s - %s\n",
369 sid_string_dbg(&member_sid),
370 sid_string_dbg(&alias_sid),
378 static int dssync_passdb_traverse_aliases(struct db_record *rec,
381 struct dssync_passdb_traverse_aliases *state =
382 (struct dssync_passdb_traverse_aliases *)private_data;
383 struct dssync_passdb *pctx =
384 talloc_get_type_abort(state->ctx->private_data,
385 struct dssync_passdb);
386 struct dssync_passdb_traverse_amembers mstate;
387 struct dssync_passdb_obj *obj;
391 if (pctx->methods == NULL) {
395 DEBUG(0,("%s[%u]...\n", state->name, state->idx));
397 obj = dssync_parse_obj(rec->value);
403 mstate.ctx = state->ctx;
404 mstate.name = "members";
406 ret = obj->members->traverse_read(obj->members,
407 dssync_passdb_traverse_amembers,
416 struct dssync_passdb_traverse_gmembers {
417 struct dssync_context *ctx;
418 struct dssync_passdb_obj *obj;
423 struct dssync_passdb_traverse_groups {
424 struct dssync_context *ctx;
429 static int dssync_passdb_traverse_gmembers(struct db_record *rec,
432 struct dssync_passdb_traverse_gmembers *state =
433 (struct dssync_passdb_traverse_gmembers *)private_data;
434 struct dssync_passdb *pctx =
435 talloc_get_type_abort(state->ctx->private_data,
436 struct dssync_passdb);
437 struct dssync_passdb_mem *mem;
439 char *nt_member = NULL;
441 struct dom_sid group_sid;
442 struct dom_sid member_sid;
443 struct samu *member = NULL;
444 const char *member_dn = NULL;
448 bool is_unix_member = false;
452 DEBUG(0,("%s[%u]...\n", state->name, state->idx));
454 group_sid = state->obj->cur->object.identifier->sid;
456 status = dom_sid_split_rid(talloc_tos(), &group_sid, NULL, &rid);
457 if (!NT_STATUS_IS_OK(status)) {
461 mem = dssync_parse_mem(rec->value);
466 member_sid = mem->cur->sid;
467 member_dn = mem->cur->dn;
469 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
470 if (mem->obj == NULL) {
471 DEBUG(0,("group[%s] member[%s] can't resolve member - ignoring\n",
472 sid_string_dbg(&group_sid),
473 is_null_sid(&member_sid)?
474 sid_string_dbg(&member_sid):
479 member_sid = mem->obj->cur->object.identifier->sid;
480 member_dn = mem->obj->cur->object.identifier->dn;
482 switch (mem->obj->type) {
483 case ATYPE_SECURITY_LOCAL_GROUP:
484 case ATYPE_SECURITY_GLOBAL_GROUP:
485 DEBUG(0, ("Group[%s] ignore member group [%s]\n",
486 sid_string_dbg(&group_sid),
487 sid_string_dbg(&member_sid)));
490 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
491 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
492 DEBUG(0, ("Group[%s] ignore distribution group [%s]\n",
493 sid_string_dbg(&group_sid),
500 if (!get_domain_group_from_sid(group_sid, &map)) {
501 DEBUG(0, ("Could not find global group %s\n",
502 sid_string_dbg(&group_sid)));
503 //return NT_STATUS_NO_SUCH_GROUP;
507 if (!(grp = getgrgid(map.gid))) {
508 DEBUG(0, ("Could not find unix group %lu\n", (unsigned long)map.gid));
509 //return NT_STATUS_NO_SUCH_GROUP;
513 DEBUG(0,("Group members of %s: ", grp->gr_name));
515 if ( !(member = samu_new(talloc_tos())) ) {
516 //return NT_STATUS_NO_MEMORY;
520 if (!pdb_getsampwsid(member, &member_sid)) {
521 DEBUG(1, ("Found bogus group member: (member_sid=%s group=%s)\n",
522 sid_string_tos(&member_sid), grp->gr_name));
527 if (pdb_get_group_rid(member) == rid) {
528 DEBUGADD(0,("%s(primary),", pdb_get_username(member)));
533 DEBUGADD(0,("%s,", pdb_get_username(member)));
534 nt_member = talloc_strdup(talloc_tos(), pdb_get_username(member));
539 unix_members = grp->gr_mem;
541 while (*unix_members) {
542 if (strcmp(*unix_members, nt_member) == 0) {
543 is_unix_member = true;
549 if (!is_unix_member && mem->active) {
550 smb_add_user_group(grp->gr_name, nt_member);
551 } else if (is_unix_member && !mem->active) {
552 smb_delete_user_group(grp->gr_name, nt_member);
558 static int dssync_passdb_traverse_groups(struct db_record *rec,
561 struct dssync_passdb_traverse_groups *state =
562 (struct dssync_passdb_traverse_groups *)private_data;
563 struct dssync_passdb *pctx =
564 talloc_get_type_abort(state->ctx->private_data,
565 struct dssync_passdb);
566 struct dssync_passdb_traverse_gmembers mstate;
567 struct dssync_passdb_obj *obj;
571 if (pctx->methods == NULL) {
575 DEBUG(0,("%s[%u]...\n", state->name, state->idx));
577 obj = dssync_parse_obj(rec->value);
583 mstate.ctx = state->ctx;
584 mstate.name = "members";
586 ret = obj->members->traverse_read(obj->members,
587 dssync_passdb_traverse_gmembers,
596 static NTSTATUS passdb_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
597 struct replUpToDateVectorBlob *new_utdv)
599 struct dssync_passdb *pctx =
600 talloc_get_type_abort(ctx->private_data,
601 struct dssync_passdb);
602 struct dssync_passdb_traverse_aliases astate;
603 struct dssync_passdb_traverse_groups gstate;
608 astate.name = "aliases";
609 ret = pctx->aliases->traverse_read(pctx->aliases,
610 dssync_passdb_traverse_aliases,
613 return NT_STATUS_INTERNAL_ERROR;
618 gstate.name = "groups";
619 ret = pctx->groups->traverse_read(pctx->groups,
620 dssync_passdb_traverse_groups,
623 return NT_STATUS_INTERNAL_ERROR;
626 TALLOC_FREE(pctx->methods);
632 /****************************************************************
633 ****************************************************************/
635 static NTSTATUS smb_create_user(TALLOC_CTX *mem_ctx,
638 struct passwd **passwd_p)
640 struct passwd *passwd;
641 char *add_script = NULL;
643 passwd = Get_Pwnam_alloc(mem_ctx, account);
649 /* Create appropriate user */
650 if (acct_flags & ACB_NORMAL) {
651 add_script = talloc_strdup(mem_ctx, lp_adduser_script());
652 } else if ( (acct_flags & ACB_WSTRUST) ||
653 (acct_flags & ACB_SVRTRUST) ||
654 (acct_flags & ACB_DOMTRUST) ) {
655 add_script = talloc_strdup(mem_ctx, lp_addmachine_script());
657 DEBUG(1, ("Unknown user type: %s\n",
658 pdb_encode_acct_ctrl(acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN)));
659 return NT_STATUS_UNSUCCESSFUL;
663 return NT_STATUS_NO_MEMORY;
668 add_script = talloc_all_string_sub(mem_ctx, add_script,
671 return NT_STATUS_NO_MEMORY;
673 add_ret = smbrun(add_script, NULL);
674 DEBUG(add_ret ? 0 : 1,("fetch_account: Running the command `%s' "
675 "gave %d\n", add_script, add_ret));
677 smb_nscd_flush_user_cache();
681 /* try and find the possible unix account again */
682 passwd = Get_Pwnam_alloc(mem_ctx, account);
684 return NT_STATUS_NO_SUCH_USER;
692 static struct drsuapi_DsReplicaAttribute *find_drsuapi_attr(
693 const struct drsuapi_DsReplicaObjectListItemEx *cur,
698 for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
699 struct drsuapi_DsReplicaAttribute *attr;
701 attr = &cur->object.attribute_ctr.attributes[i];
703 if (attr->attid == attid) {
711 static NTSTATUS find_drsuapi_attr_string(TALLOC_CTX *mem_ctx,
712 const struct drsuapi_DsReplicaObjectListItemEx *cur,
717 struct drsuapi_DsReplicaAttribute *attr;
721 attr = find_drsuapi_attr(cur, attid);
723 return NT_STATUS_PROPSET_NOT_FOUND;
726 array = talloc_array(mem_ctx, char *, attr->value_ctr.num_values);
728 return NT_STATUS_NO_MEMORY;
731 for (a = 0; a < attr->value_ctr.num_values; a++) {
732 const DATA_BLOB *blob;
735 blob = attr->value_ctr.values[a].blob;
738 return NT_STATUS_INTERNAL_DB_CORRUPTION;
741 ret = pull_string_talloc(array, NULL, 0, &array[a],
742 blob->data, blob->length,
746 return NT_STATUS_INTERNAL_ERROR;
750 *_count = attr->value_ctr.num_values;
755 static NTSTATUS find_drsuapi_attr_int32(TALLOC_CTX *mem_ctx,
756 const struct drsuapi_DsReplicaObjectListItemEx *cur,
761 struct drsuapi_DsReplicaAttribute *attr;
765 attr = find_drsuapi_attr(cur, attid);
767 return NT_STATUS_PROPSET_NOT_FOUND;
770 array = talloc_array(mem_ctx, int32_t, attr->value_ctr.num_values);
772 return NT_STATUS_NO_MEMORY;
775 for (a = 0; a < attr->value_ctr.num_values; a++) {
776 const DATA_BLOB *blob;
778 blob = attr->value_ctr.values[a].blob;
781 return NT_STATUS_INTERNAL_DB_CORRUPTION;
784 if (blob->length != 4) {
785 return NT_STATUS_INTERNAL_DB_CORRUPTION;
788 array[a] = IVAL(blob->data, 0);
791 *_count = attr->value_ctr.num_values;
796 static NTSTATUS find_drsuapi_attr_blob(TALLOC_CTX *mem_ctx,
797 const struct drsuapi_DsReplicaObjectListItemEx *cur,
802 struct drsuapi_DsReplicaAttribute *attr;
806 attr = find_drsuapi_attr(cur, attid);
808 return NT_STATUS_PROPSET_NOT_FOUND;
811 array = talloc_array(mem_ctx, DATA_BLOB, attr->value_ctr.num_values);
813 return NT_STATUS_NO_MEMORY;
816 for (a = 0; a < attr->value_ctr.num_values; a++) {
817 const DATA_BLOB *blob;
819 blob = attr->value_ctr.values[a].blob;
822 return NT_STATUS_INTERNAL_DB_CORRUPTION;
825 array[a] = data_blob_talloc(array, blob->data, blob->length);
826 if (array[a].length != blob->length) {
827 return NT_STATUS_NO_MEMORY;
830 *_count = attr->value_ctr.num_values;
835 static NTSTATUS find_drsuapi_attr_int64(TALLOC_CTX *mem_ctx,
836 const struct drsuapi_DsReplicaObjectListItemEx *cur,
841 struct drsuapi_DsReplicaAttribute *attr;
845 attr = find_drsuapi_attr(cur, attid);
847 return NT_STATUS_PROPSET_NOT_FOUND;
850 array = talloc_array(mem_ctx, int64_t, attr->value_ctr.num_values);
852 return NT_STATUS_NO_MEMORY;
855 for (a = 0; a < attr->value_ctr.num_values; a++) {
856 const DATA_BLOB *blob;
858 blob = attr->value_ctr.values[a].blob;
861 return NT_STATUS_INTERNAL_DB_CORRUPTION;
864 if (blob->length != 8) {
865 return NT_STATUS_INTERNAL_DB_CORRUPTION;
868 array[a] = BVAL(blob->data, 0);
870 *_count = attr->value_ctr.num_values;
875 static NTSTATUS find_drsuapi_attr_dn(TALLOC_CTX *mem_ctx,
876 const struct drsuapi_DsReplicaObjectListItemEx *cur,
879 struct drsuapi_DsReplicaObjectIdentifier3 **_array)
881 struct drsuapi_DsReplicaAttribute *attr;
882 struct drsuapi_DsReplicaObjectIdentifier3 *array;
885 attr = find_drsuapi_attr(cur, attid);
887 return NT_STATUS_PROPSET_NOT_FOUND;
890 array = talloc_array(mem_ctx,
891 struct drsuapi_DsReplicaObjectIdentifier3,
892 attr->value_ctr.num_values);
894 return NT_STATUS_NO_MEMORY;
897 for (a = 0; a < attr->value_ctr.num_values; a++) {
898 const DATA_BLOB *blob;
899 enum ndr_err_code ndr_err;
902 blob = attr->value_ctr.values[a].blob;
905 return NT_STATUS_INTERNAL_DB_CORRUPTION;
908 /* windows sometimes sends an extra two pad bytes here */
909 ndr_err = ndr_pull_struct_blob(blob, array, &array[a],
910 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
911 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
912 status = ndr_map_error2ntstatus(ndr_err);
916 *_count = attr->value_ctr.num_values;
921 #define GET_BLOB_EX(attr, needed) do { \
924 DATA_BLOB *_vals = NULL; \
925 attr = data_blob_null; \
926 _status = find_drsuapi_attr_blob(mem_ctx, cur, \
927 DRSUAPI_ATTID_ ## attr, \
929 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
931 _status = NT_STATUS_OK; \
935 if (!NT_STATUS_IS_OK(_status)) { \
936 DEBUG(0,(__location__ "attr[%s] %s\n", \
937 #attr, nt_errstr(_status))); \
942 talloc_free(_vals); \
943 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
944 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
946 } else if (_cnt > 1) { \
947 talloc_free(_vals); \
948 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
949 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
952 (void)talloc_steal(mem_ctx, _vals[0].data); \
954 talloc_free(_vals); \
957 #define GET_STRING_EX(attr, needed) do { \
960 char **_vals = NULL; \
962 _status = find_drsuapi_attr_string(mem_ctx, cur, \
963 DRSUAPI_ATTID_ ## attr, \
965 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
967 _status = NT_STATUS_OK; \
971 if (!NT_STATUS_IS_OK(_status)) { \
972 DEBUG(0,(__location__ "attr[%s] %s\n", \
973 #attr, nt_errstr(_status))); \
978 talloc_free(_vals); \
979 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
980 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
982 } else if (_cnt > 1) { \
983 talloc_free(_vals); \
984 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
985 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
987 attr = talloc_move(mem_ctx, &_vals[0]); \
989 talloc_free(_vals); \
992 #define GET_UINT32_EX(attr, needed) do { \
995 int32_t*_vals = NULL; \
997 _status = find_drsuapi_attr_int32(mem_ctx, cur, \
998 DRSUAPI_ATTID_ ## attr, \
1000 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1002 _status = NT_STATUS_OK; \
1006 if (!NT_STATUS_IS_OK(_status)) { \
1007 DEBUG(0,(__location__ "attr[%s] %s\n", \
1008 #attr, nt_errstr(_status))); \
1013 talloc_free(_vals); \
1014 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1015 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1017 } else if (_cnt > 1) { \
1018 talloc_free(_vals); \
1019 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1020 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1022 attr = (uint32_t)_vals[0]; \
1024 talloc_free(_vals); \
1027 #define GET_UINT64_EX(attr, needed) do { \
1030 int64_t *_vals = NULL; \
1032 _status = find_drsuapi_attr_int64(mem_ctx, cur, \
1033 DRSUAPI_ATTID_ ## attr, \
1035 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1037 _status = NT_STATUS_OK; \
1041 if (!NT_STATUS_IS_OK(_status)) { \
1042 DEBUG(0,(__location__ "attr[%s] %s\n", \
1043 #attr, nt_errstr(_status))); \
1048 talloc_free(_vals); \
1049 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1050 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1052 } else if (_cnt > 1) { \
1053 talloc_free(_vals); \
1054 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1055 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1057 attr = (uint64_t)_vals[0]; \
1059 talloc_free(_vals); \
1062 #define GET_BLOB(attr) GET_BLOB_EX(attr, false)
1063 #define GET_STRING(attr) GET_STRING_EX(attr, false)
1064 #define GET_UINT32(attr) GET_UINT32_EX(attr, false)
1065 #define GET_UINT64(attr) GET_UINT64_EX(attr, false)
1067 /* Convert a struct samu_DELTA to a struct samu. */
1068 #define STRING_CHANGED (old_string && !new_string) ||\
1069 (!old_string && new_string) ||\
1070 (old_string && new_string && (strcmp(old_string, new_string) != 0))
1072 #define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
1074 ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
1076 /****************************************************************
1077 ****************************************************************/
1079 static NTSTATUS sam_account_from_object(struct samu *account,
1080 struct drsuapi_DsReplicaObjectListItemEx *cur)
1082 TALLOC_CTX *mem_ctx = account;
1083 const char *old_string, *new_string;
1084 time_t unix_time, stored_time;
1091 NTTIME accountExpires;
1092 const char *sAMAccountName;
1093 const char *displayName;
1094 const char *homeDirectory;
1095 const char *homeDrive;
1096 const char *scriptPath;
1097 const char *profilePath;
1098 const char *description;
1099 const char *userWorkstations;
1100 const char *comment;
1101 DATA_BLOB userParameters;
1102 struct dom_sid objectSid;
1103 uint32_t primaryGroupID;
1104 uint32_t userAccountControl;
1105 DATA_BLOB logonHours;
1106 uint32_t badPwdCount;
1107 uint32_t logonCount;
1108 DATA_BLOB unicodePwd;
1112 uint32_t acct_flags;
1113 uint32_t units_per_week;
1115 memset(zero_buf, '\0', sizeof(zero_buf));
1117 objectSid = cur->object.identifier->sid;
1118 GET_STRING_EX(sAMAccountName, true);
1119 DEBUG(0,("sam_account_from_object(%s, %s) start\n",
1120 sAMAccountName, sid_string_dbg(&objectSid)));
1121 GET_UINT64(lastLogon);
1122 GET_UINT64(lastLogoff);
1123 GET_UINT64(pwdLastSet);
1124 GET_UINT64(accountExpires);
1125 GET_STRING(displayName);
1126 GET_STRING(homeDirectory);
1127 GET_STRING(homeDrive);
1128 GET_STRING(scriptPath);
1129 GET_STRING(profilePath);
1130 GET_STRING(description);
1131 GET_STRING(userWorkstations);
1132 GET_STRING(comment);
1133 GET_BLOB(userParameters);
1134 GET_UINT32(primaryGroupID);
1135 GET_UINT32(userAccountControl);
1136 GET_BLOB(logonHours);
1137 GET_UINT32(badPwdCount);
1138 GET_UINT32(logonCount);
1139 GET_BLOB(unicodePwd);
1142 status = dom_sid_split_rid(mem_ctx, &objectSid, NULL, &rid);
1143 if (!NT_STATUS_IS_OK(status)) {
1146 acct_flags = ds_uf2acb(userAccountControl);
1148 /* Username, fullname, home dir, dir drive, logon script, acct
1149 desc, workstations, profile. */
1151 if (sAMAccountName) {
1152 old_string = pdb_get_nt_username(account);
1153 new_string = sAMAccountName;
1155 if (STRING_CHANGED) {
1156 pdb_set_nt_username(account, new_string, PDB_CHANGED);
1159 /* Unix username is the same - for sanity */
1160 old_string = pdb_get_username( account );
1161 if (STRING_CHANGED) {
1162 pdb_set_username(account, new_string, PDB_CHANGED);
1167 old_string = pdb_get_fullname(account);
1168 new_string = displayName;
1171 pdb_set_fullname(account, new_string, PDB_CHANGED);
1174 if (homeDirectory) {
1175 old_string = pdb_get_homedir(account);
1176 new_string = homeDirectory;
1179 pdb_set_homedir(account, new_string, PDB_CHANGED);
1183 old_string = pdb_get_dir_drive(account);
1184 new_string = homeDrive;
1187 pdb_set_dir_drive(account, new_string, PDB_CHANGED);
1191 old_string = pdb_get_logon_script(account);
1192 new_string = scriptPath;
1195 pdb_set_logon_script(account, new_string, PDB_CHANGED);
1199 old_string = pdb_get_acct_desc(account);
1200 new_string = description;
1203 pdb_set_acct_desc(account, new_string, PDB_CHANGED);
1206 if (userWorkstations) {
1207 old_string = pdb_get_workstations(account);
1208 new_string = userWorkstations;
1211 pdb_set_workstations(account, new_string, PDB_CHANGED);
1215 old_string = pdb_get_profile_path(account);
1216 new_string = profilePath;
1219 pdb_set_profile_path(account, new_string, PDB_CHANGED);
1222 if (userParameters.data) {
1224 old_string = pdb_get_munged_dial(account);
1225 newstr = (userParameters.length == 0) ? NULL :
1226 base64_encode_data_blob(talloc_tos(), userParameters);
1228 if (STRING_CHANGED_NC(old_string, newstr))
1229 pdb_set_munged_dial(account, newstr, PDB_CHANGED);
1230 TALLOC_FREE(newstr);
1233 /* User and group sid */
1234 if (rid != 0 && pdb_get_user_rid(account) != rid) {
1235 pdb_set_user_sid_from_rid(account, rid, PDB_CHANGED);
1237 if (primaryGroupID != 0 && pdb_get_group_rid(account) != primaryGroupID) {
1238 pdb_set_group_sid_from_rid(account, primaryGroupID, PDB_CHANGED);
1241 /* Logon and password information */
1242 if (!nt_time_is_zero(&lastLogon)) {
1243 unix_time = nt_time_to_unix(lastLogon);
1244 stored_time = pdb_get_logon_time(account);
1245 if (stored_time != unix_time)
1246 pdb_set_logon_time(account, unix_time, PDB_CHANGED);
1249 if (!nt_time_is_zero(&lastLogoff)) {
1250 unix_time = nt_time_to_unix(lastLogoff);
1251 stored_time = pdb_get_logoff_time(account);
1252 if (stored_time != unix_time)
1253 pdb_set_logoff_time(account, unix_time,PDB_CHANGED);
1257 units_per_week = logonHours.length * 8;
1259 if (pdb_get_logon_divs(account) != units_per_week) {
1260 pdb_set_logon_divs(account, units_per_week, PDB_CHANGED);
1263 /* Logon Hours Len */
1264 if (units_per_week/8 != pdb_get_hours_len(account)) {
1265 pdb_set_hours_len(account, units_per_week/8, PDB_CHANGED);
1269 if (logonHours.data) {
1270 char oldstr[44], newstr[44];
1271 pdb_sethexhours(oldstr, pdb_get_hours(account));
1272 pdb_sethexhours(newstr, logonHours.data);
1273 if (!strequal(oldstr, newstr)) {
1274 pdb_set_hours(account, logonHours.data, PDB_CHANGED);
1278 if (pdb_get_bad_password_count(account) != badPwdCount)
1279 pdb_set_bad_password_count(account, badPwdCount, PDB_CHANGED);
1281 if (pdb_get_logon_count(account) != logonCount)
1282 pdb_set_logon_count(account, logonCount, PDB_CHANGED);
1284 if (!nt_time_is_zero(&pwdLastSet)) {
1285 unix_time = nt_time_to_unix(pwdLastSet);
1286 stored_time = pdb_get_pass_last_set_time(account);
1287 if (stored_time != unix_time)
1288 pdb_set_pass_last_set_time(account, unix_time, PDB_CHANGED);
1290 /* no last set time, make it now */
1291 pdb_set_pass_last_set_time(account, time(NULL), PDB_CHANGED);
1294 if (!nt_time_is_zero(&accountExpires)) {
1295 unix_time = nt_time_to_unix(accountExpires);
1296 stored_time = pdb_get_kickoff_time(account);
1297 if (stored_time != unix_time)
1298 pdb_set_kickoff_time(account, unix_time, PDB_CHANGED);
1301 /* Decode hashes from password hash
1302 Note that win2000 may send us all zeros for the hashes if it doesn't
1303 think this channel is secure enough - don't set the passwords at all
1306 if (dBCSPwd.length == 16 && memcmp(dBCSPwd.data, zero_buf, 16) != 0) {
1307 pdb_set_lanman_passwd(account, dBCSPwd.data, PDB_CHANGED);
1310 if (unicodePwd.length == 16 && memcmp(unicodePwd.data, zero_buf, 16) != 0) {
1311 pdb_set_nt_passwd(account, unicodePwd.data, PDB_CHANGED);
1316 /* TODO: account expiry time */
1318 pdb_set_acct_ctrl(account, acct_flags, PDB_CHANGED);
1320 pdb_set_domain(account, lp_workgroup(), PDB_CHANGED);
1322 DEBUG(0,("sam_account_from_object(%s, %s) done\n",
1323 sAMAccountName, sid_string_dbg(&objectSid)));
1324 return NT_STATUS_OK;
1327 /****************************************************************
1328 ****************************************************************/
1330 static NTSTATUS handle_account_object(struct dssync_passdb *pctx,
1331 TALLOC_CTX *mem_ctx,
1332 struct dssync_passdb_obj *obj)
1334 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1337 struct samu *sam_account=NULL;
1340 struct dom_sid user_sid;
1341 struct dom_sid group_sid;
1342 struct passwd *passwd = NULL;
1343 uint32_t acct_flags;
1346 const char *sAMAccountName;
1347 uint32_t sAMAccountType;
1348 uint32_t userAccountControl;
1350 user_sid = cur->object.identifier->sid;
1351 GET_STRING_EX(sAMAccountName, true);
1352 GET_UINT32_EX(sAMAccountType, true);
1353 GET_UINT32_EX(userAccountControl, true);
1355 status = dom_sid_split_rid(mem_ctx, &user_sid, NULL, &rid);
1356 if (!NT_STATUS_IS_OK(status)) {
1360 fstrcpy(account, sAMAccountName);
1361 if (rid == DOMAIN_RID_GUEST) {
1363 * pdb_getsampwsid() has special handling for DOMAIN_RID_GUEST
1364 * that's why we need to ignore it here.
1366 * pdb_smbpasswd.c also has some DOMAIN_RID_GUEST related
1369 DEBUG(0,("Ignore %s - %s\n", account, sid_string_dbg(&user_sid)));
1370 return NT_STATUS_OK;
1372 DEBUG(0,("Creating account: %s\n", account));
1374 if ( !(sam_account = samu_new(mem_ctx)) ) {
1375 return NT_STATUS_NO_MEMORY;
1378 acct_flags = ds_uf2acb(userAccountControl);
1379 status = smb_create_user(sam_account, acct_flags, account, &passwd);
1380 if (!NT_STATUS_IS_OK(status)) {
1381 DEBUG(0,("Could not create posix account info for '%s'- %s\n",
1382 account, nt_errstr(status)));
1383 TALLOC_FREE(sam_account);
1387 DEBUG(3, ("Attempting to find SID %s for user %s in the passdb\n",
1388 sid_string_dbg(&user_sid), account));
1389 if (!pdb_getsampwsid(sam_account, &user_sid)) {
1390 sam_account_from_object(sam_account, cur);
1391 DEBUG(3, ("Attempting to add user SID %s for user %s in the passdb\n",
1392 sid_string_dbg(&user_sid),
1393 pdb_get_username(sam_account)));
1394 if (!NT_STATUS_IS_OK(pdb_add_sam_account(sam_account))) {
1395 DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n",
1397 TALLOC_FREE(sam_account);
1398 return NT_STATUS_ACCESS_DENIED;
1401 sam_account_from_object(sam_account, cur);
1402 DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n",
1403 sid_string_dbg(&user_sid),
1404 pdb_get_username(sam_account)));
1405 if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) {
1406 DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n",
1408 TALLOC_FREE(sam_account);
1409 return NT_STATUS_ACCESS_DENIED;
1413 if (pdb_get_group_sid(sam_account) == NULL) {
1414 TALLOC_FREE(sam_account);
1415 return NT_STATUS_UNSUCCESSFUL;
1418 group_sid = *pdb_get_group_sid(sam_account);
1420 if (!pdb_getgrsid(&map, group_sid)) {
1421 DEBUG(0, ("Primary group of %s has no mapping!\n",
1422 pdb_get_username(sam_account)));
1424 if (map.gid != passwd->pw_gid) {
1425 if (!(grp = getgrgid(map.gid))) {
1426 DEBUG(0, ("Could not find unix group %lu for user %s (group SID=%s)\n",
1427 (unsigned long)map.gid, pdb_get_username(sam_account),
1428 sid_string_dbg(&group_sid)));
1430 smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
1436 DEBUG(1, ("No unix user for this account (%s), cannot adjust mappings\n",
1437 pdb_get_username(sam_account)));
1440 TALLOC_FREE(sam_account);
1441 return NT_STATUS_OK;
1444 /****************************************************************
1445 ****************************************************************/
1447 static NTSTATUS handle_alias_object(struct dssync_passdb *pctx,
1448 TALLOC_CTX *mem_ctx,
1449 struct dssync_passdb_obj *obj)
1451 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1455 struct group *grp = NULL;
1456 struct dom_sid group_sid;
1458 struct dom_sid *dom_sid = NULL;
1463 const char *sAMAccountName;
1464 uint32_t sAMAccountType;
1466 const char *description;
1468 uint32_t num_members = 0;
1469 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1471 group_sid = cur->object.identifier->sid;
1472 GET_STRING_EX(sAMAccountName, true);
1473 GET_UINT32_EX(sAMAccountType, true);
1474 GET_UINT32_EX(groupType, true);
1475 GET_STRING(description);
1477 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1478 &num_members, &members);
1479 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1480 status = NT_STATUS_OK;
1482 if (!NT_STATUS_IS_OK(status)) {
1486 fstrcpy(name, sAMAccountName);
1487 fstrcpy(comment, description);
1489 dom_sid_split_rid(mem_ctx, &group_sid, &dom_sid, &rid);
1491 sid_to_fstring(sid_string, &group_sid);
1492 DEBUG(0,("Creating alias[%s] - %s members[%u]\n",
1493 name, sid_string, num_members));
1495 status = dssync_insert_obj(pctx, pctx->aliases, obj);
1496 if (!NT_STATUS_IS_OK(status)) {
1500 if (pdb_getgrsid(&map, group_sid)) {
1501 if ( map.gid != -1 )
1502 grp = getgrgid(map.gid);
1509 /* No group found from mapping, find it from its name. */
1510 if ((grp = getgrnam(name)) == NULL) {
1512 /* No appropriate group found, create one */
1514 DEBUG(0,("Creating unix group: '%s'\n", name));
1516 if (smb_create_group(name, &gid) != 0)
1517 return NT_STATUS_ACCESS_DENIED;
1519 if ((grp = getgrgid(gid)) == NULL)
1520 return NT_STATUS_ACCESS_DENIED;
1524 map.gid = grp->gr_gid;
1525 map.sid = group_sid;
1527 if (dom_sid_equal(dom_sid, &global_sid_Builtin)) {
1529 * pdb_ldap does not like SID_NAME_WKN_GRP...
1531 * map.sid_name_use = SID_NAME_WKN_GRP;
1533 map.sid_name_use = SID_NAME_ALIAS;
1535 map.sid_name_use = SID_NAME_ALIAS;
1538 fstrcpy(map.nt_name, name);
1540 fstrcpy(map.comment, comment);
1542 fstrcpy(map.comment, "");
1546 pdb_add_group_mapping_entry(&map);
1548 pdb_update_group_mapping_entry(&map);
1550 for (i=0; i < num_members; i++) {
1551 struct dssync_passdb_mem *mem;
1553 status = dssync_create_mem(pctx, obj,
1556 if (!NT_STATUS_IS_OK(status)) {
1561 return NT_STATUS_OK;
1564 /****************************************************************
1565 ****************************************************************/
1567 static NTSTATUS handle_group_object(struct dssync_passdb *pctx,
1568 TALLOC_CTX *mem_ctx,
1569 struct dssync_passdb_obj *obj)
1571 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1575 struct group *grp = NULL;
1576 struct dom_sid group_sid;
1581 const char *sAMAccountName;
1582 uint32_t sAMAccountType;
1584 const char *description;
1586 uint32_t num_members = 0;
1587 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1589 group_sid = cur->object.identifier->sid;
1590 GET_STRING_EX(sAMAccountName, true);
1591 GET_UINT32_EX(sAMAccountType, true);
1592 GET_UINT32_EX(groupType, true);
1593 GET_STRING(description);
1595 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1596 &num_members, &members);
1597 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1598 status = NT_STATUS_OK;
1600 if (!NT_STATUS_IS_OK(status)) {
1604 fstrcpy(name, sAMAccountName);
1605 fstrcpy(comment, description);
1607 sid_to_fstring(sid_string, &group_sid);
1608 DEBUG(0,("Creating group[%s] - %s members [%u]\n",
1609 name, sid_string, num_members));
1611 status = dssync_insert_obj(pctx, pctx->groups, obj);
1612 if (!NT_STATUS_IS_OK(status)) {
1616 if (pdb_getgrsid(&map, group_sid)) {
1617 if ( map.gid != -1 )
1618 grp = getgrgid(map.gid);
1625 /* No group found from mapping, find it from its name. */
1626 if ((grp = getgrnam(name)) == NULL) {
1628 /* No appropriate group found, create one */
1630 DEBUG(0,("Creating unix group: '%s'\n", name));
1632 if (smb_create_group(name, &gid) != 0)
1633 return NT_STATUS_ACCESS_DENIED;
1635 if ((grp = getgrnam(name)) == NULL)
1636 return NT_STATUS_ACCESS_DENIED;
1640 map.gid = grp->gr_gid;
1641 map.sid = group_sid;
1642 map.sid_name_use = SID_NAME_DOM_GRP;
1643 fstrcpy(map.nt_name, name);
1645 fstrcpy(map.comment, comment);
1647 fstrcpy(map.comment, "");
1651 pdb_add_group_mapping_entry(&map);
1653 pdb_update_group_mapping_entry(&map);
1655 for (i=0; i < num_members; i++) {
1656 struct dssync_passdb_mem *mem;
1658 status = dssync_create_mem(pctx, obj,
1661 if (!NT_STATUS_IS_OK(status)) {
1666 return NT_STATUS_OK;
1669 /****************************************************************
1670 ****************************************************************/
1672 static NTSTATUS handle_interdomain_trust_object(struct dssync_passdb *pctx,
1673 TALLOC_CTX *mem_ctx,
1674 struct dssync_passdb_obj *obj)
1676 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1677 DEBUG(0,("trust: %s\n", cur->object.identifier->dn));
1678 return NT_STATUS_NOT_IMPLEMENTED;
1681 /****************************************************************
1682 ****************************************************************/
1684 struct dssync_object_table_t {
1686 NTSTATUS (*fn) (struct dssync_passdb *pctx,
1687 TALLOC_CTX *mem_ctx,
1688 struct dssync_passdb_obj *obj);
1691 static const struct dssync_object_table_t dssync_object_table[] = {
1692 { ATYPE_NORMAL_ACCOUNT, handle_account_object },
1693 { ATYPE_WORKSTATION_TRUST, handle_account_object },
1694 { ATYPE_SECURITY_LOCAL_GROUP, handle_alias_object },
1695 { ATYPE_SECURITY_GLOBAL_GROUP, handle_group_object },
1696 { ATYPE_INTERDOMAIN_TRUST, handle_interdomain_trust_object },
1699 /****************************************************************
1700 ****************************************************************/
1702 static NTSTATUS parse_object(struct dssync_passdb *pctx,
1703 TALLOC_CTX *mem_ctx,
1704 struct drsuapi_DsReplicaObjectListItemEx *cur)
1706 NTSTATUS status = NT_STATUS_OK;
1710 struct drsuapi_DsReplicaAttribute *attr;
1714 uint32_t sam_type = 0;
1716 DEBUG(3, ("parsing object '%s'\n", cur->object.identifier->dn));
1718 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
1720 attr = &cur->object.attribute_ctr.attributes[i];
1722 if (attr->value_ctr.num_values != 1) {
1726 if (!attr->value_ctr.values[0].blob) {
1730 blob = attr->value_ctr.values[0].blob;
1732 switch (attr->attid) {
1733 case DRSUAPI_ATTID_sAMAccountName:
1734 pull_string_talloc(mem_ctx, NULL, 0, &name,
1735 blob->data, blob->length,
1738 case DRSUAPI_ATTID_sAMAccountType:
1739 sam_type = IVAL(blob->data, 0);
1741 case DRSUAPI_ATTID_userAccountControl:
1742 uacc = IVAL(blob->data, 0);
1749 for (a=0; a < ARRAY_SIZE(dssync_object_table); a++) {
1750 if (sam_type == dssync_object_table[a].type) {
1751 if (dssync_object_table[a].fn) {
1752 struct dssync_passdb_obj *obj;
1753 status = dssync_create_obj(pctx, pctx->all,
1754 sam_type, cur, &obj);
1755 if (!NT_STATUS_IS_OK(status)) {
1758 status = dssync_object_table[a].fn(pctx,
1769 static NTSTATUS parse_link(struct dssync_passdb *pctx,
1770 TALLOC_CTX *mem_ctx,
1771 struct drsuapi_DsReplicaLinkedAttribute *cur)
1773 struct drsuapi_DsReplicaObjectIdentifier3 *id3;
1774 const DATA_BLOB *blob;
1775 enum ndr_err_code ndr_err;
1777 bool active = false;
1778 struct dssync_passdb_mem *mem;
1779 struct dssync_passdb_obj *obj;
1781 if (cur->attid != DRSUAPI_ATTID_member) {
1782 return NT_STATUS_OK;
1785 if (cur->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
1789 DEBUG(3, ("parsing link '%s' - %s\n",
1790 cur->identifier->dn, active?"adding":"deleting"));
1792 blob = cur->value.blob;
1795 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1798 obj = dssync_search_obj_by_guid(pctx, pctx->all, &cur->identifier->guid);
1800 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1803 id3 = talloc_zero(obj, struct drsuapi_DsReplicaObjectIdentifier3);
1805 return NT_STATUS_NO_MEMORY;
1808 /* windows sometimes sends an extra two pad bytes here */
1809 ndr_err = ndr_pull_struct_blob(blob, id3, id3,
1810 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
1811 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1812 status = ndr_map_error2ntstatus(ndr_err);
1816 status = dssync_create_mem(pctx, obj,
1819 if (!NT_STATUS_IS_OK(status)) {
1823 return NT_STATUS_OK;
1826 /****************************************************************
1827 ****************************************************************/
1829 static NTSTATUS passdb_process_objects(struct dssync_context *ctx,
1830 TALLOC_CTX *mem_ctx,
1831 struct drsuapi_DsReplicaObjectListItemEx *cur,
1832 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1834 NTSTATUS status = NT_STATUS_OK;
1835 struct dssync_passdb *pctx =
1836 talloc_get_type_abort(ctx->private_data,
1837 struct dssync_passdb);
1839 for (; cur; cur = cur->next_object) {
1840 status = parse_object(pctx, mem_ctx, cur);
1841 if (!NT_STATUS_IS_OK(status)) {
1850 /****************************************************************
1851 ****************************************************************/
1853 static NTSTATUS passdb_process_links(struct dssync_context *ctx,
1854 TALLOC_CTX *mem_ctx,
1856 struct drsuapi_DsReplicaLinkedAttribute *links,
1857 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1859 NTSTATUS status = NT_STATUS_OK;
1860 struct dssync_passdb *pctx =
1861 talloc_get_type_abort(ctx->private_data,
1862 struct dssync_passdb);
1865 for (i = 0; i < count; i++) {
1866 status = parse_link(pctx, mem_ctx, &links[i]);
1867 if (!NT_STATUS_IS_OK(status)) {
1876 /****************************************************************
1877 ****************************************************************/
1879 const struct dssync_ops libnet_dssync_passdb_ops = {
1880 .startup = passdb_startup,
1881 .process_objects = passdb_process_objects,
1882 .process_links = passdb_process_links,
1883 .finish = passdb_finish,