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 "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"
27 #include "dbwrap/dbwrap.h"
28 #include "dbwrap/dbwrap_rbt.h"
29 #include "../libds/common/flag_mapping.h"
32 /****************************************************************
33 ****************************************************************/
35 struct dssync_passdb {
36 struct pdb_methods *methods;
37 struct db_context *all;
38 struct db_context *aliases;
39 struct db_context *groups;
42 struct dssync_passdb_obj {
43 struct dssync_passdb_obj *self;
45 struct drsuapi_DsReplicaObjectListItemEx *cur;
48 struct db_context *members;
51 struct dssync_passdb_mem {
52 struct dssync_passdb_mem *self;
54 struct drsuapi_DsReplicaObjectIdentifier3 *cur;
55 struct dssync_passdb_obj *obj;
60 static NTSTATUS dssync_insert_obj(struct dssync_passdb *pctx,
61 struct db_context *db,
62 struct dssync_passdb_obj *obj)
65 struct db_record *rec;
68 rec = dbwrap_fetch_locked(db, talloc_tos(), obj->key);
70 return NT_STATUS_NO_MEMORY;
73 value = dbwrap_record_get_value(rec);
74 if (value.dsize != 0) {
78 status = dbwrap_record_store(rec, obj->data, TDB_INSERT);
79 if (!NT_STATUS_IS_OK(status)) {
87 static struct dssync_passdb_obj *dssync_parse_obj(const TDB_DATA data)
89 struct dssync_passdb_obj *obj;
91 if (data.dsize != sizeof(obj)) {
96 * we need to copy the pointer to avoid alignment problems
99 memcpy(&obj, data.dptr, sizeof(obj));
101 return talloc_get_type_abort(obj, struct dssync_passdb_obj);
104 static struct dssync_passdb_obj *dssync_search_obj_by_guid(struct dssync_passdb *pctx,
105 struct db_context *db,
106 const struct GUID *guid)
108 struct dssync_passdb_obj *obj;
113 key = make_tdb_data((const uint8_t *)(const void *)guid,
116 status = dbwrap_fetch(db, talloc_tos(), key, &data);
117 if (!NT_STATUS_IS_OK(status)) {
121 obj = dssync_parse_obj(data);
125 static NTSTATUS dssync_create_obj(struct dssync_passdb *pctx,
126 struct db_context *db,
128 struct drsuapi_DsReplicaObjectListItemEx *cur,
129 struct dssync_passdb_obj **_obj)
132 struct dssync_passdb_obj *obj;
134 obj = talloc_zero(pctx, struct dssync_passdb_obj);
136 return NT_STATUS_NO_MEMORY;
141 obj->key = make_tdb_data((const uint8_t *)(void *)&cur->object.identifier->guid,
142 sizeof(cur->object.identifier->guid));
143 obj->data = make_tdb_data((const uint8_t *)(void *)&obj->self,
146 obj->members = db_open_rbt(obj);
147 if (obj->members == NULL) {
148 return NT_STATUS_NO_MEMORY;
151 status = dssync_insert_obj(pctx, db, obj);
152 if (!NT_STATUS_IS_OK(status)) {
160 static NTSTATUS dssync_insert_mem(struct dssync_passdb *pctx,
161 struct dssync_passdb_obj *obj,
162 struct dssync_passdb_mem *mem)
165 struct db_record *rec;
168 rec = dbwrap_fetch_locked(obj->members, talloc_tos(), mem->key);
170 return NT_STATUS_NO_MEMORY;
173 value = dbwrap_record_get_value(rec);
174 if (value.dsize != 0) {
178 status = dbwrap_record_store(rec, mem->data, TDB_INSERT);
179 if (!NT_STATUS_IS_OK(status)) {
187 static NTSTATUS dssync_create_mem(struct dssync_passdb *pctx,
188 struct dssync_passdb_obj *obj,
190 struct drsuapi_DsReplicaObjectIdentifier3 *cur,
191 struct dssync_passdb_mem **_mem)
194 struct dssync_passdb_mem *mem;
196 mem = talloc_zero(pctx, struct dssync_passdb_mem);
198 return NT_STATUS_NO_MEMORY;
202 mem->active = active;
204 mem->key = make_tdb_data((const uint8_t *)(void *)&cur->guid,
206 mem->data = make_tdb_data((const uint8_t *)(void *)&mem->self,
209 status = dssync_insert_mem(pctx, obj, mem);
210 if (!NT_STATUS_IS_OK(status)) {
218 static struct dssync_passdb_mem *dssync_parse_mem(const TDB_DATA data)
220 struct dssync_passdb_mem *mem;
222 if (data.dsize != sizeof(mem)) {
227 * we need to copy the pointer to avoid alignment problems
230 memcpy(&mem, data.dptr, sizeof(mem));
232 return talloc_get_type_abort(mem, struct dssync_passdb_mem);
235 static NTSTATUS passdb_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
236 struct replUpToDateVectorBlob **pold_utdv)
239 struct dssync_passdb *pctx;
241 pctx = talloc_zero(mem_ctx, struct dssync_passdb);
243 return NT_STATUS_NO_MEMORY;
246 if (ctx->output_filename) {
247 status = make_pdb_method_name(&pctx->methods, ctx->output_filename);
249 status = make_pdb_method_name(&pctx->methods, lp_passdb_backend());
252 if (!NT_STATUS_IS_OK(status)) {
256 pctx->all = db_open_rbt(pctx);
257 if (pctx->all == NULL) {
258 return NT_STATUS_NO_MEMORY;
260 pctx->aliases = db_open_rbt(pctx);
261 if (pctx->aliases == NULL) {
262 return NT_STATUS_NO_MEMORY;
264 pctx->groups = db_open_rbt(pctx);
265 if (pctx->groups == NULL) {
266 return NT_STATUS_NO_MEMORY;
269 ctx->private_data = pctx;
274 /****************************************************************
275 ****************************************************************/
277 struct dssync_passdb_traverse_amembers {
278 struct dssync_context *ctx;
279 struct dssync_passdb_obj *obj;
284 struct dssync_passdb_traverse_aliases {
285 struct dssync_context *ctx;
290 static int dssync_passdb_traverse_amembers(struct db_record *rec,
293 struct dssync_passdb_traverse_amembers *state =
294 (struct dssync_passdb_traverse_amembers *)private_data;
295 struct dssync_passdb *pctx =
296 talloc_get_type_abort(state->ctx->private_data,
297 struct dssync_passdb);
298 struct dssync_passdb_mem *mem;
300 struct dom_sid alias_sid;
301 struct dom_sid member_sid;
302 const char *member_dn;
305 struct dom_sid *members;
306 bool is_member = false;
312 alias_sid = state->obj->cur->object.identifier->sid;
314 value = dbwrap_record_get_value(rec);
315 mem = dssync_parse_mem(value);
320 member_sid = mem->cur->sid;
321 member_dn = mem->cur->dn;
323 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
324 if (mem->obj == NULL) {
325 DEBUG(0,("alias[%s] member[%s] can't resolve member - ignoring\n",
326 sid_string_dbg(&alias_sid),
327 is_null_sid(&member_sid)?
328 sid_string_dbg(&member_sid):
333 switch (mem->obj->type) {
334 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
335 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
336 DEBUG(0, ("alias[%s] ignore distribution group [%s]\n",
337 sid_string_dbg(&alias_sid),
344 DEBUG(0,("alias[%s] member[%s]\n",
345 sid_string_dbg(&alias_sid),
346 sid_string_dbg(&member_sid)));
348 status = pdb_enum_aliasmem(&alias_sid, talloc_tos(),
349 &members, &num_members);
350 if (!NT_STATUS_IS_OK(status)) {
351 DEBUG(0, ("Could not find current alias members %s - %s\n",
352 sid_string_dbg(&alias_sid),
357 for (i=0; i < num_members; i++) {
360 match = dom_sid_equal(&members[i], &member_sid);
367 status = NT_STATUS_OK;
369 if (!is_member && mem->active) {
371 pdb_add_aliasmem(&alias_sid, &member_sid);
372 } else if (is_member && !mem->active) {
374 pdb_del_aliasmem(&alias_sid, &member_sid);
376 if (!NT_STATUS_IS_OK(status)) {
377 DEBUG(0, ("Could not %s %s as alias members of %s - %s\n",
379 sid_string_dbg(&member_sid),
380 sid_string_dbg(&alias_sid),
388 static int dssync_passdb_traverse_aliases(struct db_record *rec,
391 struct dssync_passdb_traverse_aliases *state =
392 (struct dssync_passdb_traverse_aliases *)private_data;
393 struct dssync_passdb *pctx =
394 talloc_get_type_abort(state->ctx->private_data,
395 struct dssync_passdb);
396 struct dssync_passdb_traverse_amembers mstate;
397 struct dssync_passdb_obj *obj;
402 if (pctx->methods == NULL) {
406 value = dbwrap_record_get_value(rec);
407 obj = dssync_parse_obj(value);
413 mstate.ctx = state->ctx;
414 mstate.name = "members";
416 status = dbwrap_traverse_read(obj->members,
417 dssync_passdb_traverse_amembers,
419 if (!NT_STATUS_IS_OK(status)) {
426 struct dssync_passdb_traverse_gmembers {
427 struct dssync_context *ctx;
428 struct dssync_passdb_obj *obj;
433 struct dssync_passdb_traverse_groups {
434 struct dssync_context *ctx;
439 static int dssync_passdb_traverse_gmembers(struct db_record *rec,
442 struct dssync_passdb_traverse_gmembers *state =
443 (struct dssync_passdb_traverse_gmembers *)private_data;
444 struct dssync_passdb *pctx =
445 talloc_get_type_abort(state->ctx->private_data,
446 struct dssync_passdb);
447 struct dssync_passdb_mem *mem;
449 char *nt_member = NULL;
451 struct dom_sid group_sid;
452 struct dom_sid member_sid;
453 struct samu *member = NULL;
454 const char *member_dn = NULL;
458 bool is_unix_member = false;
463 group_sid = state->obj->cur->object.identifier->sid;
465 status = dom_sid_split_rid(talloc_tos(), &group_sid, NULL, &rid);
466 if (!NT_STATUS_IS_OK(status)) {
470 value = dbwrap_record_get_value(rec);
472 mem = dssync_parse_mem(value);
477 member_sid = mem->cur->sid;
478 member_dn = mem->cur->dn;
480 mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
481 if (mem->obj == NULL) {
482 DEBUG(0,("group[%s] member[%s] can't resolve member - ignoring\n",
483 sid_string_dbg(&group_sid),
484 is_null_sid(&member_sid)?
485 sid_string_dbg(&member_sid):
490 member_sid = mem->obj->cur->object.identifier->sid;
491 member_dn = mem->obj->cur->object.identifier->dn;
493 switch (mem->obj->type) {
494 case ATYPE_SECURITY_LOCAL_GROUP:
495 case ATYPE_SECURITY_GLOBAL_GROUP:
496 DEBUG(0, ("Group[%s] ignore member group [%s]\n",
497 sid_string_dbg(&group_sid),
498 sid_string_dbg(&member_sid)));
501 case ATYPE_DISTRIBUTION_LOCAL_GROUP:
502 case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
503 DEBUG(0, ("Group[%s] ignore distribution group [%s]\n",
504 sid_string_dbg(&group_sid),
511 if (!get_domain_group_from_sid(group_sid, &map)) {
512 DEBUG(0, ("Could not find global group %s\n",
513 sid_string_dbg(&group_sid)));
514 //return NT_STATUS_NO_SUCH_GROUP;
518 if (!(grp = getgrgid(map.gid))) {
519 DEBUG(0, ("Could not find unix group %lu\n", (unsigned long)map.gid));
520 //return NT_STATUS_NO_SUCH_GROUP;
524 DEBUG(0,("Group members of %s: ", grp->gr_name));
526 if ( !(member = samu_new(talloc_tos())) ) {
527 //return NT_STATUS_NO_MEMORY;
531 if (!pdb_getsampwsid(member, &member_sid)) {
532 DEBUG(1, ("Found bogus group member: (member_sid=%s group=%s)\n",
533 sid_string_tos(&member_sid), grp->gr_name));
538 if (pdb_get_group_rid(member) == rid) {
539 DEBUGADD(0,("%s(primary),", pdb_get_username(member)));
544 DEBUGADD(0,("%s,", pdb_get_username(member)));
545 nt_member = talloc_strdup(talloc_tos(), pdb_get_username(member));
550 unix_members = grp->gr_mem;
552 while (*unix_members) {
553 if (strcmp(*unix_members, nt_member) == 0) {
554 is_unix_member = true;
560 if (!is_unix_member && mem->active) {
561 smb_add_user_group(grp->gr_name, nt_member);
562 } else if (is_unix_member && !mem->active) {
563 smb_delete_user_group(grp->gr_name, nt_member);
569 static int dssync_passdb_traverse_groups(struct db_record *rec,
572 struct dssync_passdb_traverse_groups *state =
573 (struct dssync_passdb_traverse_groups *)private_data;
574 struct dssync_passdb *pctx =
575 talloc_get_type_abort(state->ctx->private_data,
576 struct dssync_passdb);
577 struct dssync_passdb_traverse_gmembers mstate;
578 struct dssync_passdb_obj *obj;
583 if (pctx->methods == NULL) {
587 value = dbwrap_record_get_value(rec);
589 obj = dssync_parse_obj(value);
595 mstate.ctx = state->ctx;
596 mstate.name = "members";
598 status = dbwrap_traverse_read(obj->members,
599 dssync_passdb_traverse_gmembers,
601 if (!NT_STATUS_IS_OK(status)) {
608 static NTSTATUS passdb_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
609 struct replUpToDateVectorBlob *new_utdv)
611 struct dssync_passdb *pctx =
612 talloc_get_type_abort(ctx->private_data,
613 struct dssync_passdb);
614 struct dssync_passdb_traverse_aliases astate;
615 struct dssync_passdb_traverse_groups gstate;
620 astate.name = "aliases";
621 status = dbwrap_traverse_read(pctx->aliases,
622 dssync_passdb_traverse_aliases,
624 if (!NT_STATUS_IS_OK(status)) {
625 return NT_STATUS_INTERNAL_ERROR;
630 gstate.name = "groups";
631 status = dbwrap_traverse_read(pctx->groups,
632 dssync_passdb_traverse_groups,
634 if (!NT_STATUS_IS_OK(status)) {
635 return NT_STATUS_INTERNAL_ERROR;
638 TALLOC_FREE(pctx->methods);
644 /****************************************************************
645 ****************************************************************/
647 static NTSTATUS smb_create_user(TALLOC_CTX *mem_ctx,
650 struct passwd **passwd_p)
652 struct passwd *passwd;
653 char *add_script = NULL;
655 passwd = Get_Pwnam_alloc(mem_ctx, account);
661 /* Create appropriate user */
662 if (acct_flags & ACB_NORMAL) {
663 add_script = talloc_strdup(mem_ctx, lp_adduser_script());
664 } else if ( (acct_flags & ACB_WSTRUST) ||
665 (acct_flags & ACB_SVRTRUST) ||
666 (acct_flags & ACB_DOMTRUST) ) {
667 add_script = talloc_strdup(mem_ctx, lp_addmachine_script());
669 DEBUG(1, ("Unknown user type: %s\n",
670 pdb_encode_acct_ctrl(acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN)));
671 return NT_STATUS_UNSUCCESSFUL;
675 return NT_STATUS_NO_MEMORY;
680 add_script = talloc_all_string_sub(mem_ctx, add_script,
683 return NT_STATUS_NO_MEMORY;
685 add_ret = smbrun(add_script, NULL);
686 DEBUG(add_ret ? 0 : 1,("fetch_account: Running the command `%s' "
687 "gave %d\n", add_script, add_ret));
689 smb_nscd_flush_user_cache();
693 /* try and find the possible unix account again */
694 passwd = Get_Pwnam_alloc(mem_ctx, account);
696 return NT_STATUS_NO_SUCH_USER;
704 static struct drsuapi_DsReplicaAttribute *find_drsuapi_attr(
705 const struct drsuapi_DsReplicaObjectListItemEx *cur,
710 for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
711 struct drsuapi_DsReplicaAttribute *attr;
713 attr = &cur->object.attribute_ctr.attributes[i];
715 if (attr->attid == attid) {
723 static NTSTATUS find_drsuapi_attr_string(TALLOC_CTX *mem_ctx,
724 const struct drsuapi_DsReplicaObjectListItemEx *cur,
729 struct drsuapi_DsReplicaAttribute *attr;
733 attr = find_drsuapi_attr(cur, attid);
735 return NT_STATUS_PROPSET_NOT_FOUND;
738 array = talloc_array(mem_ctx, char *, attr->value_ctr.num_values);
740 return NT_STATUS_NO_MEMORY;
743 for (a = 0; a < attr->value_ctr.num_values; a++) {
744 const DATA_BLOB *blob;
747 blob = attr->value_ctr.values[a].blob;
750 return NT_STATUS_INTERNAL_DB_CORRUPTION;
753 ret = pull_string_talloc(array, NULL, 0, &array[a],
754 blob->data, blob->length,
758 return NT_STATUS_INTERNAL_ERROR;
762 *_count = attr->value_ctr.num_values;
767 static NTSTATUS find_drsuapi_attr_int32(TALLOC_CTX *mem_ctx,
768 const struct drsuapi_DsReplicaObjectListItemEx *cur,
773 struct drsuapi_DsReplicaAttribute *attr;
777 attr = find_drsuapi_attr(cur, attid);
779 return NT_STATUS_PROPSET_NOT_FOUND;
782 array = talloc_array(mem_ctx, int32_t, attr->value_ctr.num_values);
784 return NT_STATUS_NO_MEMORY;
787 for (a = 0; a < attr->value_ctr.num_values; a++) {
788 const DATA_BLOB *blob;
790 blob = attr->value_ctr.values[a].blob;
793 return NT_STATUS_INTERNAL_DB_CORRUPTION;
796 if (blob->length != 4) {
797 return NT_STATUS_INTERNAL_DB_CORRUPTION;
800 array[a] = IVAL(blob->data, 0);
803 *_count = attr->value_ctr.num_values;
808 static NTSTATUS find_drsuapi_attr_blob(TALLOC_CTX *mem_ctx,
809 const struct drsuapi_DsReplicaObjectListItemEx *cur,
814 struct drsuapi_DsReplicaAttribute *attr;
818 attr = find_drsuapi_attr(cur, attid);
820 return NT_STATUS_PROPSET_NOT_FOUND;
823 array = talloc_array(mem_ctx, DATA_BLOB, attr->value_ctr.num_values);
825 return NT_STATUS_NO_MEMORY;
828 for (a = 0; a < attr->value_ctr.num_values; a++) {
829 const DATA_BLOB *blob;
831 blob = attr->value_ctr.values[a].blob;
834 return NT_STATUS_INTERNAL_DB_CORRUPTION;
837 array[a] = data_blob_talloc(array, blob->data, blob->length);
838 if (array[a].length != blob->length) {
839 return NT_STATUS_NO_MEMORY;
842 *_count = attr->value_ctr.num_values;
847 static NTSTATUS find_drsuapi_attr_int64(TALLOC_CTX *mem_ctx,
848 const struct drsuapi_DsReplicaObjectListItemEx *cur,
853 struct drsuapi_DsReplicaAttribute *attr;
857 attr = find_drsuapi_attr(cur, attid);
859 return NT_STATUS_PROPSET_NOT_FOUND;
862 array = talloc_array(mem_ctx, int64_t, attr->value_ctr.num_values);
864 return NT_STATUS_NO_MEMORY;
867 for (a = 0; a < attr->value_ctr.num_values; a++) {
868 const DATA_BLOB *blob;
870 blob = attr->value_ctr.values[a].blob;
873 return NT_STATUS_INTERNAL_DB_CORRUPTION;
876 if (blob->length != 8) {
877 return NT_STATUS_INTERNAL_DB_CORRUPTION;
880 array[a] = BVAL(blob->data, 0);
882 *_count = attr->value_ctr.num_values;
887 static NTSTATUS find_drsuapi_attr_dn(TALLOC_CTX *mem_ctx,
888 const struct drsuapi_DsReplicaObjectListItemEx *cur,
891 struct drsuapi_DsReplicaObjectIdentifier3 **_array)
893 struct drsuapi_DsReplicaAttribute *attr;
894 struct drsuapi_DsReplicaObjectIdentifier3 *array;
897 attr = find_drsuapi_attr(cur, attid);
899 return NT_STATUS_PROPSET_NOT_FOUND;
902 array = talloc_array(mem_ctx,
903 struct drsuapi_DsReplicaObjectIdentifier3,
904 attr->value_ctr.num_values);
906 return NT_STATUS_NO_MEMORY;
909 for (a = 0; a < attr->value_ctr.num_values; a++) {
910 const DATA_BLOB *blob;
911 enum ndr_err_code ndr_err;
914 blob = attr->value_ctr.values[a].blob;
917 return NT_STATUS_INTERNAL_DB_CORRUPTION;
920 /* windows sometimes sends an extra two pad bytes here */
921 ndr_err = ndr_pull_struct_blob(blob, array, &array[a],
922 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
923 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
924 status = ndr_map_error2ntstatus(ndr_err);
928 *_count = attr->value_ctr.num_values;
933 #define GET_BLOB_EX(attr, needed) do { \
936 DATA_BLOB *_vals = NULL; \
937 attr = data_blob_null; \
938 _status = find_drsuapi_attr_blob(mem_ctx, cur, \
939 DRSUAPI_ATTID_ ## attr, \
941 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
943 _status = NT_STATUS_OK; \
947 if (!NT_STATUS_IS_OK(_status)) { \
948 DEBUG(0,(__location__ "attr[%s] %s\n", \
949 #attr, nt_errstr(_status))); \
954 talloc_free(_vals); \
955 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
956 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
958 } else if (_cnt > 1) { \
959 talloc_free(_vals); \
960 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
961 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
964 (void)talloc_steal(mem_ctx, _vals[0].data); \
966 talloc_free(_vals); \
969 #define GET_STRING_EX(attr, needed) do { \
972 char **_vals = NULL; \
974 _status = find_drsuapi_attr_string(mem_ctx, cur, \
975 DRSUAPI_ATTID_ ## attr, \
977 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
979 _status = NT_STATUS_OK; \
983 if (!NT_STATUS_IS_OK(_status)) { \
984 DEBUG(0,(__location__ "attr[%s] %s\n", \
985 #attr, nt_errstr(_status))); \
990 talloc_free(_vals); \
991 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
992 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
994 } else if (_cnt > 1) { \
995 talloc_free(_vals); \
996 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
997 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
999 attr = talloc_move(mem_ctx, &_vals[0]); \
1001 talloc_free(_vals); \
1004 #define GET_UINT32_EX(attr, needed) do { \
1007 int32_t*_vals = NULL; \
1009 _status = find_drsuapi_attr_int32(mem_ctx, cur, \
1010 DRSUAPI_ATTID_ ## attr, \
1012 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1014 _status = NT_STATUS_OK; \
1018 if (!NT_STATUS_IS_OK(_status)) { \
1019 DEBUG(0,(__location__ "attr[%s] %s\n", \
1020 #attr, nt_errstr(_status))); \
1025 talloc_free(_vals); \
1026 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1027 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1029 } else if (_cnt > 1) { \
1030 talloc_free(_vals); \
1031 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1032 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1034 attr = (uint32_t)_vals[0]; \
1036 talloc_free(_vals); \
1039 #define GET_UINT64_EX(attr, needed) do { \
1042 int64_t *_vals = NULL; \
1044 _status = find_drsuapi_attr_int64(mem_ctx, cur, \
1045 DRSUAPI_ATTID_ ## attr, \
1047 if (NT_STATUS_EQUAL(_status, NT_STATUS_PROPSET_NOT_FOUND)) { \
1049 _status = NT_STATUS_OK; \
1053 if (!NT_STATUS_IS_OK(_status)) { \
1054 DEBUG(0,(__location__ "attr[%s] %s\n", \
1055 #attr, nt_errstr(_status))); \
1060 talloc_free(_vals); \
1061 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1062 return NT_STATUS_OBJECT_NAME_NOT_FOUND; \
1064 } else if (_cnt > 1) { \
1065 talloc_free(_vals); \
1066 DEBUG(0,(__location__ "attr[%s] count[%u]\n", #attr, _cnt)); \
1067 return NT_STATUS_INTERNAL_DB_CORRUPTION; \
1069 attr = (uint64_t)_vals[0]; \
1071 talloc_free(_vals); \
1074 #define GET_BLOB(attr) GET_BLOB_EX(attr, false)
1075 #define GET_STRING(attr) GET_STRING_EX(attr, false)
1076 #define GET_UINT32(attr) GET_UINT32_EX(attr, false)
1077 #define GET_UINT64(attr) GET_UINT64_EX(attr, false)
1079 /* Convert a struct samu_DELTA to a struct samu. */
1080 #define STRING_CHANGED (old_string && !new_string) ||\
1081 (!old_string && new_string) ||\
1082 (old_string && new_string && (strcmp(old_string, new_string) != 0))
1084 #define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
1086 ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
1088 /****************************************************************
1089 ****************************************************************/
1091 static NTSTATUS sam_account_from_object(struct samu *account,
1092 struct drsuapi_DsReplicaObjectListItemEx *cur)
1094 TALLOC_CTX *mem_ctx = account;
1095 const char *old_string, *new_string;
1096 time_t unix_time, stored_time;
1103 NTTIME accountExpires;
1104 const char *sAMAccountName;
1105 const char *displayName;
1106 const char *homeDirectory;
1107 const char *homeDrive;
1108 const char *scriptPath;
1109 const char *profilePath;
1110 const char *description;
1111 const char *userWorkstations;
1112 const char *comment;
1113 DATA_BLOB userParameters;
1114 struct dom_sid objectSid;
1115 uint32_t primaryGroupID;
1116 uint32_t userAccountControl;
1117 DATA_BLOB logonHours;
1118 uint32_t badPwdCount;
1119 uint32_t logonCount;
1120 DATA_BLOB unicodePwd;
1124 uint32_t acct_flags;
1125 uint32_t units_per_week;
1127 memset(zero_buf, '\0', sizeof(zero_buf));
1129 objectSid = cur->object.identifier->sid;
1130 GET_STRING_EX(sAMAccountName, true);
1131 DEBUG(0,("sam_account_from_object(%s, %s) start\n",
1132 sAMAccountName, sid_string_dbg(&objectSid)));
1133 GET_UINT64(lastLogon);
1134 GET_UINT64(lastLogoff);
1135 GET_UINT64(pwdLastSet);
1136 GET_UINT64(accountExpires);
1137 GET_STRING(displayName);
1138 GET_STRING(homeDirectory);
1139 GET_STRING(homeDrive);
1140 GET_STRING(scriptPath);
1141 GET_STRING(profilePath);
1142 GET_STRING(description);
1143 GET_STRING(userWorkstations);
1144 GET_STRING(comment);
1145 GET_BLOB(userParameters);
1146 GET_UINT32(primaryGroupID);
1147 GET_UINT32(userAccountControl);
1148 GET_BLOB(logonHours);
1149 GET_UINT32(badPwdCount);
1150 GET_UINT32(logonCount);
1151 GET_BLOB(unicodePwd);
1154 status = dom_sid_split_rid(mem_ctx, &objectSid, NULL, &rid);
1155 if (!NT_STATUS_IS_OK(status)) {
1158 acct_flags = ds_uf2acb(userAccountControl);
1160 /* Username, fullname, home dir, dir drive, logon script, acct
1161 desc, workstations, profile. */
1163 if (sAMAccountName) {
1164 old_string = pdb_get_nt_username(account);
1165 new_string = sAMAccountName;
1167 if (STRING_CHANGED) {
1168 pdb_set_nt_username(account, new_string, PDB_CHANGED);
1171 /* Unix username is the same - for sanity */
1172 old_string = pdb_get_username( account );
1173 if (STRING_CHANGED) {
1174 pdb_set_username(account, new_string, PDB_CHANGED);
1179 old_string = pdb_get_fullname(account);
1180 new_string = displayName;
1183 pdb_set_fullname(account, new_string, PDB_CHANGED);
1186 if (homeDirectory) {
1187 old_string = pdb_get_homedir(account);
1188 new_string = homeDirectory;
1191 pdb_set_homedir(account, new_string, PDB_CHANGED);
1195 old_string = pdb_get_dir_drive(account);
1196 new_string = homeDrive;
1199 pdb_set_dir_drive(account, new_string, PDB_CHANGED);
1203 old_string = pdb_get_logon_script(account);
1204 new_string = scriptPath;
1207 pdb_set_logon_script(account, new_string, PDB_CHANGED);
1211 old_string = pdb_get_acct_desc(account);
1212 new_string = description;
1215 pdb_set_acct_desc(account, new_string, PDB_CHANGED);
1218 if (userWorkstations) {
1219 old_string = pdb_get_workstations(account);
1220 new_string = userWorkstations;
1223 pdb_set_workstations(account, new_string, PDB_CHANGED);
1227 old_string = pdb_get_profile_path(account);
1228 new_string = profilePath;
1231 pdb_set_profile_path(account, new_string, PDB_CHANGED);
1234 if (userParameters.data) {
1236 old_string = pdb_get_munged_dial(account);
1237 newstr = (userParameters.length == 0) ? NULL :
1238 base64_encode_data_blob(talloc_tos(), userParameters);
1240 if (STRING_CHANGED_NC(old_string, newstr))
1241 pdb_set_munged_dial(account, newstr, PDB_CHANGED);
1242 TALLOC_FREE(newstr);
1245 /* User and group sid */
1246 if (rid != 0 && pdb_get_user_rid(account) != rid) {
1247 pdb_set_user_sid_from_rid(account, rid, PDB_CHANGED);
1249 if (primaryGroupID != 0 && pdb_get_group_rid(account) != primaryGroupID) {
1250 pdb_set_group_sid_from_rid(account, primaryGroupID, PDB_CHANGED);
1253 /* Logon and password information */
1254 if (!nt_time_is_zero(&lastLogon)) {
1255 unix_time = nt_time_to_unix(lastLogon);
1256 stored_time = pdb_get_logon_time(account);
1257 if (stored_time != unix_time)
1258 pdb_set_logon_time(account, unix_time, PDB_CHANGED);
1261 if (!nt_time_is_zero(&lastLogoff)) {
1262 unix_time = nt_time_to_unix(lastLogoff);
1263 stored_time = pdb_get_logoff_time(account);
1264 if (stored_time != unix_time)
1265 pdb_set_logoff_time(account, unix_time,PDB_CHANGED);
1269 units_per_week = logonHours.length * 8;
1271 if (pdb_get_logon_divs(account) != units_per_week) {
1272 pdb_set_logon_divs(account, units_per_week, PDB_CHANGED);
1275 /* Logon Hours Len */
1276 if (units_per_week/8 != pdb_get_hours_len(account)) {
1277 pdb_set_hours_len(account, units_per_week/8, PDB_CHANGED);
1281 if (logonHours.data) {
1282 char oldstr[44], newstr[44];
1283 pdb_sethexhours(oldstr, pdb_get_hours(account));
1284 pdb_sethexhours(newstr, logonHours.data);
1285 if (!strequal(oldstr, newstr)) {
1286 pdb_set_hours(account, logonHours.data,
1287 logonHours.length, PDB_CHANGED);
1291 if (pdb_get_bad_password_count(account) != badPwdCount)
1292 pdb_set_bad_password_count(account, badPwdCount, PDB_CHANGED);
1294 if (pdb_get_logon_count(account) != logonCount)
1295 pdb_set_logon_count(account, logonCount, PDB_CHANGED);
1297 if (!nt_time_is_zero(&pwdLastSet)) {
1298 unix_time = nt_time_to_unix(pwdLastSet);
1299 stored_time = pdb_get_pass_last_set_time(account);
1300 if (stored_time != unix_time)
1301 pdb_set_pass_last_set_time(account, unix_time, PDB_CHANGED);
1303 /* no last set time, make it now */
1304 pdb_set_pass_last_set_time(account, time(NULL), PDB_CHANGED);
1307 if (!nt_time_is_zero(&accountExpires)) {
1308 unix_time = nt_time_to_unix(accountExpires);
1309 stored_time = pdb_get_kickoff_time(account);
1310 if (stored_time != unix_time)
1311 pdb_set_kickoff_time(account, unix_time, PDB_CHANGED);
1314 /* Decode hashes from password hash
1315 Note that win2000 may send us all zeros for the hashes if it doesn't
1316 think this channel is secure enough - don't set the passwords at all
1319 if (dBCSPwd.length == 16 && memcmp(dBCSPwd.data, zero_buf, 16) != 0) {
1320 pdb_set_lanman_passwd(account, dBCSPwd.data, PDB_CHANGED);
1323 if (unicodePwd.length == 16 && memcmp(unicodePwd.data, zero_buf, 16) != 0) {
1324 pdb_set_nt_passwd(account, unicodePwd.data, PDB_CHANGED);
1329 /* TODO: account expiry time */
1331 pdb_set_acct_ctrl(account, acct_flags, PDB_CHANGED);
1333 pdb_set_domain(account, lp_workgroup(), PDB_CHANGED);
1335 DEBUG(0,("sam_account_from_object(%s, %s) done\n",
1336 sAMAccountName, sid_string_dbg(&objectSid)));
1337 return NT_STATUS_OK;
1340 /****************************************************************
1341 ****************************************************************/
1343 static NTSTATUS handle_account_object(struct dssync_passdb *pctx,
1344 TALLOC_CTX *mem_ctx,
1345 struct dssync_passdb_obj *obj)
1347 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1350 struct samu *sam_account=NULL;
1353 struct dom_sid user_sid;
1354 struct dom_sid group_sid;
1355 struct passwd *passwd = NULL;
1356 uint32_t acct_flags;
1359 const char *sAMAccountName;
1360 uint32_t sAMAccountType;
1361 uint32_t userAccountControl;
1363 user_sid = cur->object.identifier->sid;
1364 GET_STRING_EX(sAMAccountName, true);
1365 GET_UINT32_EX(sAMAccountType, true);
1366 GET_UINT32_EX(userAccountControl, true);
1368 status = dom_sid_split_rid(mem_ctx, &user_sid, NULL, &rid);
1369 if (!NT_STATUS_IS_OK(status)) {
1373 fstrcpy(account, sAMAccountName);
1374 if (rid == DOMAIN_RID_GUEST) {
1376 * pdb_getsampwsid() has special handling for DOMAIN_RID_GUEST
1377 * that's why we need to ignore it here.
1379 * pdb_smbpasswd.c also has some DOMAIN_RID_GUEST related
1382 DEBUG(0,("Ignore %s - %s\n", account, sid_string_dbg(&user_sid)));
1383 return NT_STATUS_OK;
1385 DEBUG(0,("Creating account: %s\n", account));
1387 if ( !(sam_account = samu_new(mem_ctx)) ) {
1388 return NT_STATUS_NO_MEMORY;
1391 acct_flags = ds_uf2acb(userAccountControl);
1392 status = smb_create_user(sam_account, acct_flags, account, &passwd);
1393 if (!NT_STATUS_IS_OK(status)) {
1394 DEBUG(0,("Could not create posix account info for '%s'- %s\n",
1395 account, nt_errstr(status)));
1396 TALLOC_FREE(sam_account);
1400 DEBUG(3, ("Attempting to find SID %s for user %s in the passdb\n",
1401 sid_string_dbg(&user_sid), account));
1402 if (!pdb_getsampwsid(sam_account, &user_sid)) {
1403 sam_account_from_object(sam_account, cur);
1404 DEBUG(3, ("Attempting to add user SID %s for user %s in the passdb\n",
1405 sid_string_dbg(&user_sid),
1406 pdb_get_username(sam_account)));
1407 if (!NT_STATUS_IS_OK(pdb_add_sam_account(sam_account))) {
1408 DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n",
1410 TALLOC_FREE(sam_account);
1411 return NT_STATUS_ACCESS_DENIED;
1414 sam_account_from_object(sam_account, cur);
1415 DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n",
1416 sid_string_dbg(&user_sid),
1417 pdb_get_username(sam_account)));
1418 if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) {
1419 DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n",
1421 TALLOC_FREE(sam_account);
1422 return NT_STATUS_ACCESS_DENIED;
1426 if (pdb_get_group_sid(sam_account) == NULL) {
1427 TALLOC_FREE(sam_account);
1428 return NT_STATUS_UNSUCCESSFUL;
1431 group_sid = *pdb_get_group_sid(sam_account);
1433 if (!pdb_getgrsid(&map, group_sid)) {
1434 DEBUG(0, ("Primary group of %s has no mapping!\n",
1435 pdb_get_username(sam_account)));
1437 if (map.gid != passwd->pw_gid) {
1438 if (!(grp = getgrgid(map.gid))) {
1439 DEBUG(0, ("Could not find unix group %lu for user %s (group SID=%s)\n",
1440 (unsigned long)map.gid, pdb_get_username(sam_account),
1441 sid_string_dbg(&group_sid)));
1443 smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
1449 DEBUG(1, ("No unix user for this account (%s), cannot adjust mappings\n",
1450 pdb_get_username(sam_account)));
1453 TALLOC_FREE(sam_account);
1454 return NT_STATUS_OK;
1457 /****************************************************************
1458 ****************************************************************/
1460 static NTSTATUS handle_alias_object(struct dssync_passdb *pctx,
1461 TALLOC_CTX *mem_ctx,
1462 struct dssync_passdb_obj *obj)
1464 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1468 struct group *grp = NULL;
1469 struct dom_sid group_sid;
1471 struct dom_sid *dom_sid = NULL;
1476 const char *sAMAccountName;
1477 uint32_t sAMAccountType;
1479 const char *description;
1481 uint32_t num_members = 0;
1482 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1484 group_sid = cur->object.identifier->sid;
1485 GET_STRING_EX(sAMAccountName, true);
1486 GET_UINT32_EX(sAMAccountType, true);
1487 GET_UINT32_EX(groupType, true);
1488 GET_STRING(description);
1490 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1491 &num_members, &members);
1492 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1493 status = NT_STATUS_OK;
1495 if (!NT_STATUS_IS_OK(status)) {
1499 fstrcpy(name, sAMAccountName);
1500 fstrcpy(comment, description);
1502 dom_sid_split_rid(mem_ctx, &group_sid, &dom_sid, &rid);
1504 sid_to_fstring(sid_string, &group_sid);
1505 DEBUG(0,("Creating alias[%s] - %s members[%u]\n",
1506 name, sid_string, num_members));
1508 status = dssync_insert_obj(pctx, pctx->aliases, obj);
1509 if (!NT_STATUS_IS_OK(status)) {
1513 if (pdb_getgrsid(&map, group_sid)) {
1514 if ( map.gid != -1 )
1515 grp = getgrgid(map.gid);
1522 /* No group found from mapping, find it from its name. */
1523 if ((grp = getgrnam(name)) == NULL) {
1525 /* No appropriate group found, create one */
1527 DEBUG(0,("Creating unix group: '%s'\n", name));
1529 if (smb_create_group(name, &gid) != 0)
1530 return NT_STATUS_ACCESS_DENIED;
1532 if ((grp = getgrgid(gid)) == NULL)
1533 return NT_STATUS_ACCESS_DENIED;
1537 map.gid = grp->gr_gid;
1538 map.sid = group_sid;
1540 if (dom_sid_equal(dom_sid, &global_sid_Builtin)) {
1542 * pdb_ldap does not like SID_NAME_WKN_GRP...
1544 * map.sid_name_use = SID_NAME_WKN_GRP;
1546 map.sid_name_use = SID_NAME_ALIAS;
1548 map.sid_name_use = SID_NAME_ALIAS;
1551 strlcpy(map.nt_name, name, sizeof(map.nt_name));
1553 strlcpy(map.comment, comment, sizeof(map.comment));
1555 strlcpy(map.comment, "", sizeof(map.comment));
1559 pdb_add_group_mapping_entry(&map);
1561 pdb_update_group_mapping_entry(&map);
1563 for (i=0; i < num_members; i++) {
1564 struct dssync_passdb_mem *mem;
1566 status = dssync_create_mem(pctx, obj,
1569 if (!NT_STATUS_IS_OK(status)) {
1574 return NT_STATUS_OK;
1577 /****************************************************************
1578 ****************************************************************/
1580 static NTSTATUS handle_group_object(struct dssync_passdb *pctx,
1581 TALLOC_CTX *mem_ctx,
1582 struct dssync_passdb_obj *obj)
1584 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1588 struct group *grp = NULL;
1589 struct dom_sid group_sid;
1594 const char *sAMAccountName;
1595 uint32_t sAMAccountType;
1597 const char *description;
1599 uint32_t num_members = 0;
1600 struct drsuapi_DsReplicaObjectIdentifier3 *members = NULL;
1602 group_sid = cur->object.identifier->sid;
1603 GET_STRING_EX(sAMAccountName, true);
1604 GET_UINT32_EX(sAMAccountType, true);
1605 GET_UINT32_EX(groupType, true);
1606 GET_STRING(description);
1608 status = find_drsuapi_attr_dn(obj, cur, DRSUAPI_ATTID_member,
1609 &num_members, &members);
1610 if (NT_STATUS_EQUAL(status, NT_STATUS_PROPSET_NOT_FOUND)) {
1611 status = NT_STATUS_OK;
1613 if (!NT_STATUS_IS_OK(status)) {
1617 fstrcpy(name, sAMAccountName);
1618 fstrcpy(comment, description);
1620 sid_to_fstring(sid_string, &group_sid);
1621 DEBUG(0,("Creating group[%s] - %s members [%u]\n",
1622 name, sid_string, num_members));
1624 status = dssync_insert_obj(pctx, pctx->groups, obj);
1625 if (!NT_STATUS_IS_OK(status)) {
1629 if (pdb_getgrsid(&map, group_sid)) {
1630 if ( map.gid != -1 )
1631 grp = getgrgid(map.gid);
1638 /* No group found from mapping, find it from its name. */
1639 if ((grp = getgrnam(name)) == NULL) {
1641 /* No appropriate group found, create one */
1643 DEBUG(0,("Creating unix group: '%s'\n", name));
1645 if (smb_create_group(name, &gid) != 0)
1646 return NT_STATUS_ACCESS_DENIED;
1648 if ((grp = getgrnam(name)) == NULL)
1649 return NT_STATUS_ACCESS_DENIED;
1653 map.gid = grp->gr_gid;
1654 map.sid = group_sid;
1655 map.sid_name_use = SID_NAME_DOM_GRP;
1656 strlcpy(map.nt_name, name, sizeof(map.nt_name));
1658 strlcpy(map.comment, comment, sizeof(map.comment));
1660 strlcpy(map.comment, "", sizeof(map.comment));
1664 pdb_add_group_mapping_entry(&map);
1666 pdb_update_group_mapping_entry(&map);
1668 for (i=0; i < num_members; i++) {
1669 struct dssync_passdb_mem *mem;
1671 status = dssync_create_mem(pctx, obj,
1674 if (!NT_STATUS_IS_OK(status)) {
1679 return NT_STATUS_OK;
1682 /****************************************************************
1683 ****************************************************************/
1685 static NTSTATUS handle_interdomain_trust_object(struct dssync_passdb *pctx,
1686 TALLOC_CTX *mem_ctx,
1687 struct dssync_passdb_obj *obj)
1689 struct drsuapi_DsReplicaObjectListItemEx *cur = obj->cur;
1690 DEBUG(0,("trust: %s\n", cur->object.identifier->dn));
1691 return NT_STATUS_NOT_IMPLEMENTED;
1694 /****************************************************************
1695 ****************************************************************/
1697 struct dssync_object_table_t {
1699 NTSTATUS (*fn) (struct dssync_passdb *pctx,
1700 TALLOC_CTX *mem_ctx,
1701 struct dssync_passdb_obj *obj);
1704 static const struct dssync_object_table_t dssync_object_table[] = {
1705 { ATYPE_NORMAL_ACCOUNT, handle_account_object },
1706 { ATYPE_WORKSTATION_TRUST, handle_account_object },
1707 { ATYPE_SECURITY_LOCAL_GROUP, handle_alias_object },
1708 { ATYPE_SECURITY_GLOBAL_GROUP, handle_group_object },
1709 { ATYPE_INTERDOMAIN_TRUST, handle_interdomain_trust_object },
1712 /****************************************************************
1713 ****************************************************************/
1715 static NTSTATUS parse_object(struct dssync_passdb *pctx,
1716 TALLOC_CTX *mem_ctx,
1717 struct drsuapi_DsReplicaObjectListItemEx *cur)
1719 NTSTATUS status = NT_STATUS_OK;
1723 struct drsuapi_DsReplicaAttribute *attr;
1727 uint32_t sam_type = 0;
1729 DEBUG(3, ("parsing object '%s'\n", cur->object.identifier->dn));
1731 for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
1733 attr = &cur->object.attribute_ctr.attributes[i];
1735 if (attr->value_ctr.num_values != 1) {
1739 if (!attr->value_ctr.values[0].blob) {
1743 blob = attr->value_ctr.values[0].blob;
1745 switch (attr->attid) {
1746 case DRSUAPI_ATTID_sAMAccountName:
1747 pull_string_talloc(mem_ctx, NULL, 0, &name,
1748 blob->data, blob->length,
1751 case DRSUAPI_ATTID_sAMAccountType:
1752 sam_type = IVAL(blob->data, 0);
1754 case DRSUAPI_ATTID_userAccountControl:
1755 uacc = IVAL(blob->data, 0);
1762 for (a=0; a < ARRAY_SIZE(dssync_object_table); a++) {
1763 if (sam_type == dssync_object_table[a].type) {
1764 if (dssync_object_table[a].fn) {
1765 struct dssync_passdb_obj *obj;
1766 status = dssync_create_obj(pctx, pctx->all,
1767 sam_type, cur, &obj);
1768 if (!NT_STATUS_IS_OK(status)) {
1771 status = dssync_object_table[a].fn(pctx,
1782 static NTSTATUS parse_link(struct dssync_passdb *pctx,
1783 TALLOC_CTX *mem_ctx,
1784 struct drsuapi_DsReplicaLinkedAttribute *cur)
1786 struct drsuapi_DsReplicaObjectIdentifier3 *id3;
1787 const DATA_BLOB *blob;
1788 enum ndr_err_code ndr_err;
1790 bool active = false;
1791 struct dssync_passdb_mem *mem;
1792 struct dssync_passdb_obj *obj;
1794 if (cur->attid != DRSUAPI_ATTID_member) {
1795 return NT_STATUS_OK;
1798 if (cur->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) {
1802 DEBUG(3, ("parsing link '%s' - %s\n",
1803 cur->identifier->dn, active?"adding":"deleting"));
1805 blob = cur->value.blob;
1808 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1811 obj = dssync_search_obj_by_guid(pctx, pctx->all, &cur->identifier->guid);
1813 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1816 id3 = talloc_zero(obj, struct drsuapi_DsReplicaObjectIdentifier3);
1818 return NT_STATUS_NO_MEMORY;
1821 /* windows sometimes sends an extra two pad bytes here */
1822 ndr_err = ndr_pull_struct_blob(blob, id3, id3,
1823 (ndr_pull_flags_fn_t)ndr_pull_drsuapi_DsReplicaObjectIdentifier3);
1824 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1825 status = ndr_map_error2ntstatus(ndr_err);
1829 status = dssync_create_mem(pctx, obj,
1832 if (!NT_STATUS_IS_OK(status)) {
1836 return NT_STATUS_OK;
1839 /****************************************************************
1840 ****************************************************************/
1842 static NTSTATUS passdb_process_objects(struct dssync_context *ctx,
1843 TALLOC_CTX *mem_ctx,
1844 struct drsuapi_DsReplicaObjectListItemEx *cur,
1845 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1847 NTSTATUS status = NT_STATUS_OK;
1848 struct dssync_passdb *pctx =
1849 talloc_get_type_abort(ctx->private_data,
1850 struct dssync_passdb);
1852 for (; cur; cur = cur->next_object) {
1853 status = parse_object(pctx, mem_ctx, cur);
1854 if (!NT_STATUS_IS_OK(status)) {
1863 /****************************************************************
1864 ****************************************************************/
1866 static NTSTATUS passdb_process_links(struct dssync_context *ctx,
1867 TALLOC_CTX *mem_ctx,
1869 struct drsuapi_DsReplicaLinkedAttribute *links,
1870 struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1872 NTSTATUS status = NT_STATUS_OK;
1873 struct dssync_passdb *pctx =
1874 talloc_get_type_abort(ctx->private_data,
1875 struct dssync_passdb);
1878 for (i = 0; i < count; i++) {
1879 status = parse_link(pctx, mem_ctx, &links[i]);
1880 if (!NT_STATUS_IS_OK(status)) {
1889 /****************************************************************
1890 ****************************************************************/
1892 const struct dssync_ops libnet_dssync_passdb_ops = {
1893 .startup = passdb_startup,
1894 .process_objects = passdb_process_objects,
1895 .process_links = passdb_process_links,
1896 .finish = passdb_finish,