+ NTSTATUS status;
+ struct dssync_passdb *pctx;
+
+ pctx = talloc_zero(mem_ctx, struct dssync_passdb);
+ if (pctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (ctx->output_filename) {
+ status = make_pdb_method_name(&pctx->methods, ctx->output_filename);
+ } else {
+ status = make_pdb_method_name(&pctx->methods, lp_passdb_backend());
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ pctx->all = db_open_rbt(pctx);
+ if (pctx->all == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ pctx->aliases = db_open_rbt(pctx);
+ if (pctx->aliases == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ pctx->groups = db_open_rbt(pctx);
+ if (pctx->groups == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ctx->private_data = pctx;
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+struct dssync_passdb_traverse_amembers {
+ struct dssync_context *ctx;
+ struct dssync_passdb_obj *obj;
+ const char *name;
+ uint32_t idx;
+};
+
+struct dssync_passdb_traverse_aliases {
+ struct dssync_context *ctx;
+ const char *name;
+ uint32_t idx;
+};
+
+static int dssync_passdb_traverse_amembers(struct db_record *rec,
+ void *private_data)
+{
+ struct dssync_passdb_traverse_amembers *state =
+ (struct dssync_passdb_traverse_amembers *)private_data;
+ struct dssync_passdb *pctx =
+ talloc_get_type_abort(state->ctx->private_data,
+ struct dssync_passdb);
+ struct dssync_passdb_mem *mem;
+ NTSTATUS status;
+ struct dom_sid alias_sid;
+ struct dom_sid member_sid;
+ const char *member_dn;
+ size_t num_members;
+ size_t i;
+ struct dom_sid *members;
+ bool is_member = false;
+ const char *action;
+
+ state->idx++;
+
+ DEBUG(0,("%s[%u]...\n", state->name, state->idx));
+
+ alias_sid = state->obj->cur->object.identifier->sid;
+
+ mem = dssync_parse_mem(rec->value);
+ if (mem == NULL) {
+ return -1;
+ }
+
+ member_sid = mem->cur->sid;
+ member_dn = mem->cur->dn;
+
+ mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
+ if (mem->obj == NULL) {
+ DEBUG(0,("alias[%s] member[%s] can't resolve member - ignoring\n",
+ sid_string_dbg(&alias_sid),
+ is_null_sid(&member_sid)?
+ sid_string_dbg(&member_sid):
+ member_dn));
+ return 0;
+ }
+
+ switch (mem->obj->type) {
+ case ATYPE_DISTRIBUTION_LOCAL_GROUP:
+ case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
+ DEBUG(0, ("alias[%s] ignore distribution group [%s]\n",
+ sid_string_dbg(&alias_sid),
+ member_dn));
+ return 0;
+ default:
+ break;
+ }
+
+ DEBUG(0,("alias[%s] member[%s]\n",
+ sid_string_dbg(&alias_sid),
+ sid_string_dbg(&member_sid)));
+
+ status = pdb_enum_aliasmem(&alias_sid, talloc_tos(),
+ &members, &num_members);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Could not find current alias members %s - %s\n",
+ sid_string_dbg(&alias_sid),
+ nt_errstr(status)));
+ return -1;
+ }
+
+ for (i=0; i < num_members; i++) {
+ bool match;
+
+ match = dom_sid_equal(&members[i], &member_sid);
+ if (match) {
+ is_member = true;
+ break;
+ }
+ }
+
+ status = NT_STATUS_OK;
+ action = "none";
+ if (!is_member && mem->active) {
+ action = "add";
+ pdb_add_aliasmem(&alias_sid, &member_sid);
+ } else if (is_member && !mem->active) {
+ action = "delete";
+ pdb_del_aliasmem(&alias_sid, &member_sid);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Could not %s %s as alias members of %s - %s\n",
+ action,
+ sid_string_dbg(&member_sid),
+ sid_string_dbg(&alias_sid),
+ nt_errstr(status)));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int dssync_passdb_traverse_aliases(struct db_record *rec,
+ void *private_data)
+{
+ struct dssync_passdb_traverse_aliases *state =
+ (struct dssync_passdb_traverse_aliases *)private_data;
+ struct dssync_passdb *pctx =
+ talloc_get_type_abort(state->ctx->private_data,
+ struct dssync_passdb);
+ struct dssync_passdb_traverse_amembers mstate;
+ struct dssync_passdb_obj *obj;
+ int ret;
+
+ state->idx++;
+ if (pctx->methods == NULL) {
+ return -1;
+ }
+
+ DEBUG(0,("%s[%u]...\n", state->name, state->idx));
+
+ obj = dssync_parse_obj(rec->value);
+ if (obj == NULL) {
+ return -1;
+ }
+
+ ZERO_STRUCT(mstate);
+ mstate.ctx = state->ctx;
+ mstate.name = "members";
+ mstate.obj = obj;
+ ret = obj->members->traverse_read(obj->members,
+ dssync_passdb_traverse_amembers,
+ &mstate);
+ if (ret < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+struct dssync_passdb_traverse_gmembers {
+ struct dssync_context *ctx;
+ struct dssync_passdb_obj *obj;
+ const char *name;
+ uint32_t idx;
+};
+
+struct dssync_passdb_traverse_groups {
+ struct dssync_context *ctx;
+ const char *name;
+ uint32_t idx;
+};
+
+static int dssync_passdb_traverse_gmembers(struct db_record *rec,
+ void *private_data)
+{
+ struct dssync_passdb_traverse_gmembers *state =
+ (struct dssync_passdb_traverse_gmembers *)private_data;
+ struct dssync_passdb *pctx =
+ talloc_get_type_abort(state->ctx->private_data,
+ struct dssync_passdb);
+ struct dssync_passdb_mem *mem;
+ NTSTATUS status;
+ char *nt_member = NULL;
+ char **unix_members;
+ struct dom_sid group_sid;
+ struct dom_sid member_sid;
+ struct samu *member = NULL;
+ const char *member_dn = NULL;
+ GROUP_MAP map;
+ struct group *grp;
+ uint32_t rid;
+ bool is_unix_member = false;
+
+ state->idx++;
+
+ DEBUG(0,("%s[%u]...\n", state->name, state->idx));
+
+ group_sid = state->obj->cur->object.identifier->sid;
+
+ status = dom_sid_split_rid(talloc_tos(), &group_sid, NULL, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ mem = dssync_parse_mem(rec->value);
+ if (mem == NULL) {
+ return -1;
+ }
+
+ member_sid = mem->cur->sid;
+ member_dn = mem->cur->dn;
+
+ mem->obj = dssync_search_obj_by_guid(pctx, pctx->all, &mem->cur->guid);
+ if (mem->obj == NULL) {
+ DEBUG(0,("group[%s] member[%s] can't resolve member - ignoring\n",
+ sid_string_dbg(&group_sid),
+ is_null_sid(&member_sid)?
+ sid_string_dbg(&member_sid):
+ member_dn));
+ return 0;
+ }
+
+ member_sid = mem->obj->cur->object.identifier->sid;
+ member_dn = mem->obj->cur->object.identifier->dn;
+
+ switch (mem->obj->type) {
+ case ATYPE_SECURITY_LOCAL_GROUP:
+ case ATYPE_SECURITY_GLOBAL_GROUP:
+ DEBUG(0, ("Group[%s] ignore member group [%s]\n",
+ sid_string_dbg(&group_sid),
+ sid_string_dbg(&member_sid)));
+ return 0;
+
+ case ATYPE_DISTRIBUTION_LOCAL_GROUP:
+ case ATYPE_DISTRIBUTION_GLOBAL_GROUP:
+ DEBUG(0, ("Group[%s] ignore distribution group [%s]\n",
+ sid_string_dbg(&group_sid),
+ member_dn));
+ return 0;
+ default:
+ break;
+ }
+
+ if (!get_domain_group_from_sid(group_sid, &map)) {
+ DEBUG(0, ("Could not find global group %s\n",
+ sid_string_dbg(&group_sid)));
+ //return NT_STATUS_NO_SUCH_GROUP;
+ return -1;
+ }
+
+ if (!(grp = getgrgid(map.gid))) {
+ DEBUG(0, ("Could not find unix group %lu\n", (unsigned long)map.gid));
+ //return NT_STATUS_NO_SUCH_GROUP;
+ return -1;
+ }
+
+ DEBUG(0,("Group members of %s: ", grp->gr_name));
+
+ if ( !(member = samu_new(talloc_tos())) ) {
+ //return NT_STATUS_NO_MEMORY;
+ return -1;
+ }
+
+ if (!pdb_getsampwsid(member, &member_sid)) {
+ DEBUG(1, ("Found bogus group member: (member_sid=%s group=%s)\n",
+ sid_string_tos(&member_sid), grp->gr_name));
+ TALLOC_FREE(member);
+ return -1;
+ }
+
+ if (pdb_get_group_rid(member) == rid) {
+ DEBUGADD(0,("%s(primary),", pdb_get_username(member)));
+ TALLOC_FREE(member);
+ return -1;
+ }
+
+ DEBUGADD(0,("%s,", pdb_get_username(member)));
+ nt_member = talloc_strdup(talloc_tos(), pdb_get_username(member));
+ TALLOC_FREE(member);
+
+ DEBUGADD(0,("\n"));
+
+ unix_members = grp->gr_mem;
+
+ while (*unix_members) {
+ if (strcmp(*unix_members, nt_member) == 0) {
+ is_unix_member = true;
+ break;
+ }
+ unix_members += 1;
+ }
+
+ if (!is_unix_member && mem->active) {
+ smb_add_user_group(grp->gr_name, nt_member);
+ } else if (is_unix_member && !mem->active) {
+ smb_delete_user_group(grp->gr_name, nt_member);
+ }
+
+ return 0;
+}
+
+static int dssync_passdb_traverse_groups(struct db_record *rec,
+ void *private_data)
+{
+ struct dssync_passdb_traverse_groups *state =
+ (struct dssync_passdb_traverse_groups *)private_data;
+ struct dssync_passdb *pctx =
+ talloc_get_type_abort(state->ctx->private_data,
+ struct dssync_passdb);
+ struct dssync_passdb_traverse_gmembers mstate;
+ struct dssync_passdb_obj *obj;
+ int ret;
+
+ state->idx++;
+ if (pctx->methods == NULL) {
+ return -1;
+ }
+
+ DEBUG(0,("%s[%u]...\n", state->name, state->idx));
+
+ obj = dssync_parse_obj(rec->value);
+ if (obj == NULL) {
+ return -1;
+ }
+
+ ZERO_STRUCT(mstate);
+ mstate.ctx = state->ctx;
+ mstate.name = "members";
+ mstate.obj = obj;
+ ret = obj->members->traverse_read(obj->members,
+ dssync_passdb_traverse_gmembers,
+ &mstate);
+ if (ret < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static NTSTATUS passdb_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
+ struct replUpToDateVectorBlob *new_utdv)
+{
+ struct dssync_passdb *pctx =
+ talloc_get_type_abort(ctx->private_data,
+ struct dssync_passdb);
+ struct dssync_passdb_traverse_aliases astate;
+ struct dssync_passdb_traverse_groups gstate;
+ int ret;
+
+ ZERO_STRUCT(astate);
+ astate.ctx = ctx;
+ astate.name = "aliases";
+ ret = pctx->aliases->traverse_read(pctx->aliases,
+ dssync_passdb_traverse_aliases,
+ &astate);
+ if (ret < 0) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ ZERO_STRUCT(gstate);
+ gstate.ctx = ctx;
+ gstate.name = "groups";
+ ret = pctx->groups->traverse_read(pctx->groups,
+ dssync_passdb_traverse_groups,
+ &gstate);
+ if (ret < 0) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ TALLOC_FREE(pctx->methods);
+ TALLOC_FREE(pctx);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS smb_create_user(TALLOC_CTX *mem_ctx,
+ uint32_t acct_flags,
+ const char *account,
+ struct passwd **passwd_p)
+{
+ struct passwd *passwd;
+ char *add_script = NULL;
+
+ passwd = Get_Pwnam_alloc(mem_ctx, account);
+ if (passwd) {
+ *passwd_p = passwd;
+ return NT_STATUS_OK;
+ }
+
+ /* Create appropriate user */
+ if (acct_flags & ACB_NORMAL) {
+ add_script = talloc_strdup(mem_ctx, lp_adduser_script());
+ } else if ( (acct_flags & ACB_WSTRUST) ||
+ (acct_flags & ACB_SVRTRUST) ||
+ (acct_flags & ACB_DOMTRUST) ) {
+ add_script = talloc_strdup(mem_ctx, lp_addmachine_script());
+ } else {
+ DEBUG(1, ("Unknown user type: %s\n",
+ pdb_encode_acct_ctrl(acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN)));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!add_script) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (*add_script) {
+ int add_ret;
+ add_script = talloc_all_string_sub(mem_ctx, add_script,
+ "%u", account);
+ if (!add_script) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ add_ret = smbrun(add_script, NULL);
+ DEBUG(add_ret ? 0 : 1,("fetch_account: Running the command `%s' "
+ "gave %d\n", add_script, add_ret));
+ if (add_ret == 0) {
+ smb_nscd_flush_user_cache();
+ }
+ }
+
+ /* try and find the possible unix account again */
+ passwd = Get_Pwnam_alloc(mem_ctx, account);
+ if (!passwd) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ *passwd_p = passwd;
+
+ return NT_STATUS_OK;
+}
+
+static struct drsuapi_DsReplicaAttribute *find_drsuapi_attr(
+ const struct drsuapi_DsReplicaObjectListItemEx *cur,
+ uint32_t attid)
+{
+ int i = 0;
+
+ for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
+ struct drsuapi_DsReplicaAttribute *attr;
+
+ attr = &cur->object.attribute_ctr.attributes[i];
+
+ if (attr->attid == attid) {
+ return attr;
+ }
+ }
+
+ return NULL;
+}
+
+static NTSTATUS find_drsuapi_attr_string(TALLOC_CTX *mem_ctx,
+ const struct drsuapi_DsReplicaObjectListItemEx *cur,
+ uint32_t attid,
+ uint32_t *_count,
+ char ***_array)
+{
+ struct drsuapi_DsReplicaAttribute *attr;
+ char **array;
+ uint32_t a;
+
+ attr = find_drsuapi_attr(cur, attid);
+ if (attr == NULL) {
+ return NT_STATUS_PROPSET_NOT_FOUND;
+ }
+
+ array = talloc_array(mem_ctx, char *, attr->value_ctr.num_values);
+ if (array == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (a = 0; a < attr->value_ctr.num_values; a++) {
+ const DATA_BLOB *blob;
+ ssize_t ret;
+
+ blob = attr->value_ctr.values[a].blob;
+
+ if (blob == NULL) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ ret = pull_string_talloc(array, NULL, 0, &array[a],
+ blob->data, blob->length,
+ STR_UNICODE);
+ if (ret == -1) {
+ //TODO
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ }
+
+ *_count = attr->value_ctr.num_values;
+ *_array = array;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS find_drsuapi_attr_int32(TALLOC_CTX *mem_ctx,
+ const struct drsuapi_DsReplicaObjectListItemEx *cur,
+ uint32_t attid,
+ uint32_t *_count,
+ int32_t **_array)
+{
+ struct drsuapi_DsReplicaAttribute *attr;
+ int32_t *array;
+ uint32_t a;
+
+ attr = find_drsuapi_attr(cur, attid);
+ if (attr == NULL) {
+ return NT_STATUS_PROPSET_NOT_FOUND;
+ }
+
+ array = talloc_array(mem_ctx, int32_t, attr->value_ctr.num_values);
+ if (array == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (a = 0; a < attr->value_ctr.num_values; a++) {
+ const DATA_BLOB *blob;
+
+ blob = attr->value_ctr.values[a].blob;
+
+ if (blob == NULL) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ if (blob->length != 4) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ array[a] = IVAL(blob->data, 0);
+ }
+
+ *_count = attr->value_ctr.num_values;
+ *_array = array;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS find_drsuapi_attr_blob(TALLOC_CTX *mem_ctx,
+ const struct drsuapi_DsReplicaObjectListItemEx *cur,
+ uint32_t attid,
+ uint32_t *_count,
+ DATA_BLOB **_array)
+{
+ struct drsuapi_DsReplicaAttribute *attr;
+ DATA_BLOB *array;
+ uint32_t a;
+
+ attr = find_drsuapi_attr(cur, attid);
+ if (attr == NULL) {
+ return NT_STATUS_PROPSET_NOT_FOUND;
+ }
+
+ array = talloc_array(mem_ctx, DATA_BLOB, attr->value_ctr.num_values);
+ if (array == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (a = 0; a < attr->value_ctr.num_values; a++) {
+ const DATA_BLOB *blob;
+
+ blob = attr->value_ctr.values[a].blob;
+
+ if (blob == NULL) {
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ array[a] = data_blob_talloc(array, blob->data, blob->length);
+ if (array[a].length != blob->length) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ *_count = attr->value_ctr.num_values;
+ *_array = array;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS find_drsuapi_attr_int64(TALLOC_CTX *mem_ctx,
+ const struct drsuapi_DsReplicaObjectListItemEx *cur,
+ uint32_t attid,
+ uint32_t *_count,
+ int64_t **_array)
+{
+ struct drsuapi_DsReplicaAttribute *attr;
+ int64_t *array;
+ uint32_t a;