static int subtree_delete(struct ldb_module *module, struct ldb_request *req) { static const char * const attrs[] = { NULL }; int ret; struct ldb_result *res = NULL; if (ldb_dn_is_special(req->op.del.dn)) { /* do not manipulate our control entries */ return ldb_next_request(module, req); } /* see if we have any children */ ret = dsdb_module_search(module, req, &res, req->op.del.dn, LDB_SCOPE_ONELEVEL, attrs, DSDB_SEARCH_SHOW_DELETED, NULL); if (ret != LDB_SUCCESS) { talloc_free(res); return ret; } if (res->count > 0) { ldb_asprintf_errstring(ldb_module_get_ctx(module), "Cannot delete %s, not a leaf node " "(has %d children)\n", ldb_dn_get_linearized(req->op.del.dn), res->count); talloc_free(res); return LDB_ERR_NOT_ALLOWED_ON_NON_LEAF; } talloc_free(res); return ldb_next_request(module, req); }
/** * Writes schema_info structure into schemaInfo * attribute on SCHEMA partition * * @param dsdb_flags DSDB_FLAG_... flag of 0 */ static int dsdb_module_schema_info_write(struct ldb_module *ldb_module, uint32_t dsdb_flags, const struct dsdb_schema_info *schema_info, struct ldb_request *parent) { WERROR werr; int ret; DATA_BLOB ndr_blob; TALLOC_CTX *temp_ctx; temp_ctx = talloc_new(ldb_module); if (temp_ctx == NULL) { return ldb_module_oom(temp_ctx); } /* convert schema_info to a blob */ werr = dsdb_blob_from_schema_info(schema_info, temp_ctx, &ndr_blob); if (!W_ERROR_IS_OK(werr)) { talloc_free(temp_ctx); ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), __location__ ": failed to get schema_info"); return ldb_operr(ldb_module_get_ctx(ldb_module)); } /* write serialized schemaInfo into LDB */ ret = dsdb_module_schema_info_blob_write(ldb_module, dsdb_flags, &ndr_blob, parent); talloc_free(temp_ctx); return ret; }
static int prepare_modules_line(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *rootdse_msg, struct ldb_message *msg, const char *backend_attr, const char *backend_mod, const char **backend_mod_list) { int ret; const char **backend_full_list; const char *backend_dn; char *mod_list_string; char *full_string; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return ldb_oom(ldb); } if (backend_attr) { backend_dn = ldb_msg_find_attr_as_string(rootdse_msg, backend_attr, NULL); if (!backend_dn) { ldb_asprintf_errstring(ldb, "samba_dsdb_init: " "unable to read %s from %s:%s", backend_attr, ldb_dn_get_linearized(rootdse_msg->dn), ldb_errstring(ldb)); return LDB_ERR_CONSTRAINT_VIOLATION; } } else { backend_dn = "*"; } if (backend_mod) { char **b = str_list_make_single(tmp_ctx, backend_mod); backend_full_list = discard_const_p(const char *, b); } else {
/* construct msDS-UserPasswordExpiryTimeComputed */ static int construct_msds_user_password_expiry_time_computed(struct ldb_module *module, struct ldb_message *msg, enum ldb_scope scope, struct ldb_request *parent) { struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_dn *nc_root; int64_t password_expiry_time; int ret; ret = dsdb_find_nc_root(ldb, msg, msg->dn, &nc_root); if (ret != 0) { ldb_asprintf_errstring(ldb, "Failed to find NC root of DN: %s: %s", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb)); return ret; } if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) != 0) { /* Only calculate this on our default NC */ return 0; } password_expiry_time = get_msds_user_password_expiry_time_computed(module, msg, nc_root); return samdb_msg_add_int64(ldb, msg->elements, msg, "msDS-UserPasswordExpiryTimeComputed", password_expiry_time); }
static int map_rename_local_callback(struct ldb_request *req, struct ldb_reply *ares) { struct ldb_context *ldb; struct map_context *ac; int ret; ac = talloc_get_type(req->context, struct map_context); ldb = ldb_module_get_ctx(ac->module); if (!ares) { return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); } if (ares->error != LDB_SUCCESS) { return ldb_module_done(ac->req, ares->controls, ares->response, ares->error); } if (ares->type != LDB_REPLY_DONE) { ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type); return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); } /* proceed with next step */ ret = map_rename_do_fixup(ac); if (ret != LDB_SUCCESS) { return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); } return LDB_SUCCESS; }
/* construct msDS-User-Account-Control-Computed attr */ static int construct_msds_user_account_control_computed(struct ldb_module *module, struct ldb_message *msg, enum ldb_scope scope, struct ldb_request *parent) { uint32_t userAccountControl; uint32_t msDS_User_Account_Control_Computed = 0; struct ldb_context *ldb = ldb_module_get_ctx(module); NTTIME now; struct ldb_dn *nc_root; int ret; ret = dsdb_find_nc_root(ldb, msg, msg->dn, &nc_root); if (ret != 0) { ldb_asprintf_errstring(ldb, "Failed to find NC root of DN: %s: %s", ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb_module_get_ctx(module))); return ret; } if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) != 0) { /* Only calculate this on our default NC */ return 0; } /* Test account expire time */ unix_to_nt_time(&now, time(NULL)); userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0); if (!(userAccountControl & _UF_TRUST_ACCOUNTS)) { int64_t lockoutTime = ldb_msg_find_attr_as_int64(msg, "lockoutTime", 0); if (lockoutTime != 0) { int64_t lockoutDuration = samdb_search_int64(ldb, msg, 0, nc_root, "lockoutDuration", NULL); if (lockoutDuration >= 0) { msDS_User_Account_Control_Computed |= UF_LOCKOUT; } else if (lockoutTime - lockoutDuration >= now) { msDS_User_Account_Control_Computed |= UF_LOCKOUT; } } } if (!(userAccountControl & _UF_NO_EXPIRY_ACCOUNTS)) { NTTIME must_change_time = get_msds_user_password_expiry_time_computed(module, msg, nc_root); /* check for expired password */ if (must_change_time < now) { msDS_User_Account_Control_Computed |= UF_PASSWORD_EXPIRED; } } return samdb_msg_add_int64(ldb, msg->elements, msg, "msDS-User-Account-Control-Computed", msDS_User_Account_Control_Computed); }
static int ltdb_add_internal(struct ldb_module *module, const struct ldb_message *msg, bool check_single_value) { struct ldb_context *ldb = ldb_module_get_ctx(module); int ret = LDB_SUCCESS; unsigned int i; for (i=0;i<msg->num_elements;i++) { struct ldb_message_element *el = &msg->elements[i]; const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name); if (el->num_values == 0) { ldb_asprintf_errstring(ldb, "attribute '%s' on '%s' specified, but with 0 values (illegal)", el->name, ldb_dn_get_linearized(msg->dn)); return LDB_ERR_CONSTRAINT_VIOLATION; } if (check_single_value && el->num_values > 1 && ldb_tdb_single_valued(a, el)) { ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once", el->name, ldb_dn_get_linearized(msg->dn)); return LDB_ERR_CONSTRAINT_VIOLATION; } } ret = ltdb_store(module, msg, TDB_INSERT); if (ret != LDB_SUCCESS) { if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) { ldb_asprintf_errstring(ldb, "Entry %s already exists", ldb_dn_get_linearized(msg->dn)); } return ret; } ret = ltdb_index_add_new(module, msg); if (ret != LDB_SUCCESS) { return ret; } ret = ltdb_modified(module, msg->dn); return ret; }
/* make a IRPC call to the drepl task to ask it to get the RID Manager to give us another RID pool. This function just sends the message to the drepl task then returns immediately. It should be called well before we completely run out of RIDs */ static int ridalloc_poke_rid_manager(struct ldb_module *module) { struct imessaging_context *msg; struct server_id *server; struct ldb_context *ldb = ldb_module_get_ctx(module); struct loadparm_context *lp_ctx = (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"); TALLOC_CTX *tmp_ctx = talloc_new(module); NTSTATUS status; msg = imessaging_client_init(tmp_ctx, lp_ctx, ldb_get_event_context(ldb)); if (!msg) { ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to send MSG_DREPL_ALLOCATE_RID, " "unable init client messaging context"); DEBUG(3,(__location__ ": Failed to create messaging context\n")); talloc_free(tmp_ctx); return LDB_ERR_UNWILLING_TO_PERFORM; } server = irpc_servers_byname(msg, msg, "dreplsrv"); if (!server) { ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to send MSG_DREPL_ALLOCATE_RID, " "unable to locate dreplsrv"); /* this means the drepl service is not running */ talloc_free(tmp_ctx); return LDB_ERR_UNWILLING_TO_PERFORM; } status = imessaging_send(msg, server[0], MSG_DREPL_ALLOCATE_RID, NULL); /* Only error out if an error happened, not on STATUS_MORE_ENTRIES, ie a delayed message */ if (NT_STATUS_IS_ERR(status)) { ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to send MSG_DREPL_ALLOCATE_RID to dreplsrv at %s: %s", server_id_str(tmp_ctx, server), nt_errstr(status)); talloc_free(tmp_ctx); return LDB_ERR_UNWILLING_TO_PERFORM; } talloc_free(tmp_ctx); return LDB_SUCCESS; }
static int prepare_modules_line(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *rootdse_msg, struct ldb_message *msg, const char *backend_attr, const char *backend_mod, const char **backend_mod_list) { int ret; const char **backend_full_list; const char *backend_dn; char *mod_list_string; char *full_string; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return ldb_oom(ldb); } if (backend_attr) { backend_dn = ldb_msg_find_attr_as_string(rootdse_msg, backend_attr, NULL); if (!backend_dn) { ldb_asprintf_errstring(ldb, "samba_dsdb_init: " "unable to read %s from %s:%s", backend_attr, ldb_dn_get_linearized(rootdse_msg->dn), ldb_errstring(ldb)); return LDB_ERR_CONSTRAINT_VIOLATION; } } else { backend_dn = "*"; } if (backend_mod) { backend_full_list = (const char **)str_list_make_single(tmp_ctx, backend_mod); } else { backend_full_list = (const char **)str_list_make_empty(tmp_ctx); } if (!backend_full_list) { talloc_free(tmp_ctx); return ldb_oom(ldb); } backend_full_list = str_list_append_const(backend_full_list, backend_mod_list); if (!backend_full_list) { talloc_free(tmp_ctx); return ldb_oom(ldb); } mod_list_string = str_list_join(tmp_ctx, backend_full_list, ','); if (!mod_list_string) { talloc_free(tmp_ctx); return ldb_oom(ldb); } full_string = talloc_asprintf(tmp_ctx, "%s:%s", backend_dn, mod_list_string); ret = ldb_msg_add_steal_string(msg, "modules", full_string); talloc_free(tmp_ctx); return ret; }
/* * @brief log details of an error that set errno * * @param ldb ldb context, to allow logging. * @param err the value of errno. * @param desc extra text to help describe the error. * */ static void log_error(struct ldb_context *ldb, int err, const char *desc) { char buf[1024]; int e = strerror_r(err, buf, sizeof(buf)); if (e != 0) { strlcpy(buf, "Unknown error", sizeof(buf)-1); } ldb_asprintf_errstring(ldb, "Error (%d) %s - %s\n", err, buf, desc); }
/* get a new RID pool for ourselves also returns the first rid for the new pool */ static int ridalloc_new_own_pool(struct ldb_module *module, uint64_t *new_pool, struct ldb_request *parent) { TALLOC_CTX *tmp_ctx = talloc_new(module); struct ldb_dn *rid_manager_dn, *fsmo_role_dn; int ret; struct ldb_context *ldb = ldb_module_get_ctx(module); /* work out who is the RID Manager */ ret = dsdb_module_rid_manager_dn(module, tmp_ctx, &rid_manager_dn, parent); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "Failed to find RID Manager object - %s", ldb_errstring(ldb)); talloc_free(tmp_ctx); return ret; } /* find the DN of the RID Manager */ ret = dsdb_module_reference_dn(module, tmp_ctx, rid_manager_dn, "fSMORoleOwner", &fsmo_role_dn, parent); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "Failed to find fSMORoleOwner in RID Manager object - %s", ldb_errstring(ldb)); talloc_free(tmp_ctx); return ret; } if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), fsmo_role_dn) != 0) { ridalloc_poke_rid_manager(module); ldb_asprintf_errstring(ldb, "Remote RID Set allocation needs refresh"); talloc_free(tmp_ctx); return LDB_ERR_UNWILLING_TO_PERFORM; } /* grab a pool from the RID Manager object */ ret = ridalloc_rid_manager_allocate(module, rid_manager_dn, new_pool, parent); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } talloc_free(tmp_ctx); return ret; }
/** * Reads schema_info structure from schemaInfo * attribute on SCHEMA partition * * @param dsdb_flags DSDB_FLAG_... flag of 0 */ int dsdb_module_schema_info_blob_read(struct ldb_module *ldb_module, uint32_t dsdb_flags, TALLOC_CTX *mem_ctx, struct ldb_val *schema_info_blob, struct ldb_request *parent) { int ldb_err; const struct ldb_val *blob_val; struct ldb_dn *schema_dn; struct ldb_result *schema_res = NULL; static const char *schema_attrs[] = { "schemaInfo", NULL }; schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ldb_module)); if (!schema_dn) { DEBUG(0,("dsdb_module_schema_info_blob_read: no schema dn present!\n")); return ldb_operr(ldb_module_get_ctx(ldb_module)); } ldb_err = dsdb_module_search(ldb_module, mem_ctx, &schema_res, schema_dn, LDB_SCOPE_BASE, schema_attrs, dsdb_flags, parent, NULL); if (ldb_err == LDB_ERR_NO_SUCH_OBJECT) { DEBUG(0,("dsdb_module_schema_info_blob_read: Schema DN not found!\n")); talloc_free(schema_res); return ldb_err; } else if (ldb_err != LDB_SUCCESS) { DEBUG(0,("dsdb_module_schema_info_blob_read: failed to find schemaInfo attribute\n")); talloc_free(schema_res); return ldb_err; } blob_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo"); if (!blob_val) { ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), "dsdb_module_schema_info_blob_read: no schemaInfo attribute found"); talloc_free(schema_res); return LDB_ERR_NO_SUCH_ATTRIBUTE; } /* transfer .data ownership to mem_ctx */ schema_info_blob->length = blob_val->length; schema_info_blob->data = talloc_steal(mem_ctx, blob_val->data); talloc_free(schema_res); return LDB_SUCCESS; }
/* optionally perform a bind */ static int lldb_bind(struct ldb_module *module, const char *options[]) { const char *bind_mechanism; struct lldb_private *lldb; struct ldb_context *ldb = ldb_module_get_ctx(module); int ret; bind_mechanism = ldb_options_find(ldb, options, "bindMech"); if (bind_mechanism == NULL) { /* no bind wanted */ return LDB_SUCCESS; } lldb = talloc_get_type(ldb_module_get_private(module), struct lldb_private); if (strcmp(bind_mechanism, "simple") == 0) { const char *bind_id, *bind_secret; bind_id = ldb_options_find(ldb, options, "bindID"); bind_secret = ldb_options_find(ldb, options, "bindSecret"); if (bind_id == NULL || bind_secret == NULL) { ldb_asprintf_errstring(ldb, "simple bind requires bindID and bindSecret"); return LDB_ERR_OPERATIONS_ERROR; } ret = ldap_simple_bind_s(lldb->ldap, bind_id, bind_secret); if (ret != LDAP_SUCCESS) { ldb_asprintf_errstring(ldb, "bind failed: %s", ldap_err2string(ret)); return ret; } return LDB_SUCCESS; } ldb_asprintf_errstring(ldb, "bind failed: unknown mechanism %s", bind_mechanism); return LDB_ERR_INAPPROPRIATE_AUTHENTICATION; }
int dsdb_check_access_on_dn_internal(struct ldb_context *ldb, struct ldb_result *acl_res, TALLOC_CTX *mem_ctx, struct security_token *token, struct ldb_dn *dn, uint32_t access_mask, const struct GUID *guid) { struct security_descriptor *sd = NULL; struct dom_sid *sid = NULL; struct object_tree *root = NULL; NTSTATUS status; uint32_t access_granted; int ret; ret = dsdb_get_sd_from_ldb_message(ldb, mem_ctx, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { return ldb_operr(ldb); } sid = samdb_result_dom_sid(mem_ctx, acl_res->msgs[0], "objectSid"); if (guid) { if (!insert_in_object_tree(mem_ctx, guid, access_mask, NULL, &root)) { return ldb_operr(ldb); } } status = sec_access_check_ds(sd, token, access_mask, &access_granted, root, sid); if (!NT_STATUS_IS_OK(status)) { dsdb_acl_debug(sd, token, dn, true, 10); ldb_asprintf_errstring(ldb, "dsdb_access: Access check failed on %s", ldb_dn_get_linearized(dn)); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } return LDB_SUCCESS; }
/* * Initialize metadata. Load metadata.tdb. * If missing, create it and fill in sequence number */ int partition_metadata_init(struct ldb_module *module) { struct partition_private_data *data; int ret; data = talloc_get_type_abort(ldb_module_get_private(module), struct partition_private_data); data->metadata = talloc_zero(data, struct partition_metadata); if (data->metadata == NULL) { return ldb_module_oom(module); } ret = partition_metadata_open(module, false); if (ret == LDB_SUCCESS) { goto end; } /* metadata.tdb does not exist, create it */ DEBUG(2, ("partition_metadata: Migrating partition metadata: " "open of metadata.tdb gave: %s\n", ldb_errstring(ldb_module_get_ctx(module)))); ret = partition_metadata_open(module, true); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb_module_get_ctx(module), "partition_metadata: " "Migrating partition metadata: " "create of metadata.tdb gave: %s\n", ldb_errstring(ldb_module_get_ctx(module))); talloc_free(data->metadata); data->metadata = NULL; goto end; } ret = partition_metadata_set_sequence_number(module); if (ret != LDB_SUCCESS) { talloc_free(data->metadata); data->metadata = NULL; } end: return ret; }
/* return the dn key to be used for an index caller frees */ static struct ldb_dn *ltdb_index_key(struct ldb_context *ldb, const char *attr, const struct ldb_val *value) { struct ldb_dn *ret; struct ldb_val v; const struct ldb_schema_attribute *a; char *attr_folded; int r; attr_folded = ldb_attr_casefold(ldb, attr); if (!attr_folded) { return NULL; } a = ldb_schema_attribute_by_name(ldb, attr); r = a->syntax->canonicalise_fn(ldb, ldb, value, &v); if (r != LDB_SUCCESS) { const char *errstr = ldb_errstring(ldb); /* canonicalisation can be refused. For example, a attribute that takes wildcards will refuse to canonicalise if the value contains a wildcard */ ldb_asprintf_errstring(ldb, "Failed to create index key for attribute '%s':%s%s%s", attr, ldb_strerror(r), (errstr?":":""), (errstr?errstr:"")); talloc_free(attr_folded); return NULL; } if (ldb_should_b64_encode(&v)) { char *vstr = ldb_base64_encode(ldb, (char *)v.data, v.length); if (!vstr) return NULL; ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s::%s", LTDB_INDEX, attr_folded, vstr); talloc_free(vstr); } else { ret = ldb_dn_new_fmt(ldb, ldb, "%s:%s:%.*s", LTDB_INDEX, attr_folded, (int)v.length, (char *)v.data); } if (v.data != value->data) { talloc_free(v.data); } talloc_free(attr_folded); return ret; }
/** * Reads schema_info structure from schemaInfo * attribute on SCHEMA partition */ static int dsdb_module_schema_info_read(struct ldb_module *ldb_module, uint32_t dsdb_flags, TALLOC_CTX *mem_ctx, struct dsdb_schema_info **_schema_info, struct ldb_request *parent) { int ret; DATA_BLOB ndr_blob; TALLOC_CTX *temp_ctx; WERROR werr; temp_ctx = talloc_new(mem_ctx); if (temp_ctx == NULL) { return ldb_module_oom(ldb_module); } /* read serialized schemaInfo from LDB */ ret = dsdb_module_schema_info_blob_read(ldb_module, dsdb_flags, temp_ctx, &ndr_blob, parent); if (ret != LDB_SUCCESS) { talloc_free(temp_ctx); return ret; } /* convert NDR blob to dsdb_schema_info object */ werr = dsdb_schema_info_from_blob(&ndr_blob, mem_ctx, _schema_info); talloc_free(temp_ctx); if (W_ERROR_EQUAL(werr, WERR_DS_NO_ATTRIBUTE_OR_VALUE)) { return LDB_ERR_NO_SUCH_ATTRIBUTE; } if (!W_ERROR_IS_OK(werr)) { ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), __location__ ": failed to get schema_info"); return ldb_operr(ldb_module_get_ctx(ldb_module)); } return LDB_SUCCESS; }
static int ltdb_add_internal(struct ldb_module *module, const struct ldb_message *msg) { struct ldb_context *ldb = ldb_module_get_ctx(module); int ret; ret = ltdb_check_special_dn(module, msg); if (ret != LDB_SUCCESS) { return ret; } if (ltdb_cache_load(module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } ret = ltdb_store(module, msg, TDB_INSERT); if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) { ldb_asprintf_errstring(ldb, "Entry %s already exists", ldb_dn_get_linearized(msg->dn)); return ret; } if (ret == LDB_SUCCESS) { ret = ltdb_index_one(module, msg, 1); if (ret != LDB_SUCCESS) { return ret; } ret = ltdb_modified(module, msg->dn); if (ret != LDB_SUCCESS) { return ret; } } return ret; }
/** * Writes schema_info structure into schemaInfo * attribute on SCHEMA partition * * @param dsdb_flags DSDB_FLAG_... flag of 0 */ int dsdb_module_schema_info_blob_write(struct ldb_module *ldb_module, uint32_t dsdb_flags, struct ldb_val *schema_info_blob, struct ldb_request *parent) { int ldb_err; struct ldb_message *msg; TALLOC_CTX *temp_ctx; temp_ctx = talloc_new(ldb_module); if (temp_ctx == NULL) { return ldb_module_oom(ldb_module); } /* write serialized schemaInfo into LDB */ ldb_err = dsdb_schema_info_write_prepare(ldb_module_get_ctx(ldb_module), schema_info_blob, temp_ctx, &msg); if (ldb_err != LDB_SUCCESS) { talloc_free(temp_ctx); return ldb_err; } ldb_err = dsdb_module_modify(ldb_module, msg, dsdb_flags, parent); talloc_free(temp_ctx); if (ldb_err != LDB_SUCCESS) { ldb_asprintf_errstring(ldb_module_get_ctx(ldb_module), "dsdb_module_schema_info_blob_write: dsdb_replace failed: %s (%s)\n", ldb_strerror(ldb_err), ldb_errstring(ldb_module_get_ctx(ldb_module))); return ldb_err; } return LDB_SUCCESS; }
/** * Prepares ldb_msg to be used for updating schemaInfo value in DB */ static int dsdb_schema_info_write_prepare(struct ldb_context *ldb, struct ldb_val *schema_info_blob, TALLOC_CTX *mem_ctx, struct ldb_message **_msg) { int ldb_err; struct ldb_message *msg; struct ldb_dn *schema_dn; struct ldb_message_element *return_el; schema_dn = ldb_get_schema_basedn(ldb); if (!schema_dn) { DEBUG(0,("dsdb_schema_info_write_prepare: no schema dn present\n")); return ldb_operr(ldb); } /* prepare ldb_msg to update schemaInfo */ msg = ldb_msg_new(mem_ctx); if (msg == NULL) { return ldb_oom(ldb); } msg->dn = schema_dn; ldb_err = ldb_msg_add_value(msg, "schemaInfo", schema_info_blob, &return_el); if (ldb_err != 0) { ldb_asprintf_errstring(ldb, "dsdb_schema_info_write_prepare: ldb_msg_add_value failed - %s\n", ldb_strerror(ldb_err)); talloc_free(msg); return ldb_err; } /* mark schemaInfo element for replacement */ return_el->flags = LDB_FLAG_MOD_REPLACE; *_msg = msg; return LDB_SUCCESS; }
static int acl_allowedAttributes(struct ldb_module *module, struct ldb_message *sd_msg, struct ldb_message *msg, struct acl_context *ac) { struct ldb_message_element *oc_el; struct ldb_context *ldb = ldb_module_get_ctx(module); const struct dsdb_schema *schema = dsdb_get_schema(ldb); TALLOC_CTX *mem_ctx; const char **attr_list; int i, ret; /* If we don't have a schema yet, we can't do anything... */ if (schema == NULL) { return LDB_SUCCESS; } /* Must remove any existing attribute */ if (ac->allowedAttributes) { ldb_msg_remove_attr(msg, "allowedAttributes"); } mem_ctx = talloc_new(msg); if (!mem_ctx) { ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; } oc_el = ldb_msg_find_element(sd_msg, "objectClass"); attr_list = dsdb_full_attribute_list(mem_ctx, schema, oc_el, DSDB_SCHEMA_ALL); if (!attr_list) { ldb_asprintf_errstring(ldb, "acl: Failed to get list of attributes"); talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } if (ac->allowedAttributes) { for (i=0; attr_list && attr_list[i]; i++) { ldb_msg_add_string(msg, "allowedAttributes", attr_list[i]); } } if (ac->allowedAttributesEffective) { struct security_descriptor *sd; struct dom_sid *sid = NULL; ldb_msg_remove_attr(msg, "allowedAttributesEffective"); if (ac->user_type == SECURITY_SYSTEM) { for (i=0; attr_list && attr_list[i]; i++) { ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]); } return LDB_SUCCESS; } ret = get_sd_from_ldb_message(mem_ctx, sd_msg, &sd); if (ret != LDB_SUCCESS) { return ret; } ret = get_dom_sid_from_ldb_message(mem_ctx, sd_msg, &sid); if (ret != LDB_SUCCESS) { return ret; } for (i=0; attr_list && attr_list[i]; i++) { struct dsdb_attribute *attr = dsdb_attribute_by_lDAPDisplayName(schema, attr_list[i]); if (!attr) { return LDB_ERR_OPERATIONS_ERROR; } /* remove constructed attributes */ if (attr->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED || attr->systemOnly || (attr->linkID != 0 && attr->linkID % 2 != 0 )) { continue; } ret = acl_check_access_on_attribute(module, msg, sd, sid, SEC_ADS_WRITE_PROP, attr); if (ret == LDB_SUCCESS) { ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]); } } } return LDB_SUCCESS; }
/* modify a record - internal interface yuck - this is O(n^2). Luckily n is usually small so we probably get away with it, but if we ever have really large attribute lists then we'll need to look at this again 'req' is optional, and is used to specify controls if supplied */ int ltdb_modify_internal(struct ldb_module *module, const struct ldb_message *msg, struct ldb_request *req) { struct ldb_context *ldb = ldb_module_get_ctx(module); void *data = ldb_module_get_private(module); struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private); TDB_DATA tdb_key, tdb_data; struct ldb_val ldb_data; struct ldb_message *msg2; unsigned int i, j, k; int ret = LDB_SUCCESS, idx; struct ldb_control *control_permissive = NULL; if (req) { control_permissive = ldb_request_get_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID); } tdb_key = ltdb_key(module, msg->dn); if (!tdb_key.dptr) { return LDB_ERR_OTHER; } tdb_data = tdb_fetch(ltdb->tdb, tdb_key); if (!tdb_data.dptr) { talloc_free(tdb_key.dptr); return ltdb_err_map(tdb_error(ltdb->tdb)); } msg2 = ldb_msg_new(tdb_key.dptr); if (msg2 == NULL) { free(tdb_data.dptr); ret = LDB_ERR_OTHER; goto done; } ldb_data.data = tdb_data.dptr; ldb_data.length = tdb_data.dsize; ret = ldb_unpack_data(ldb_module_get_ctx(module), &ldb_data, msg2); free(tdb_data.dptr); if (ret == -1) { ret = LDB_ERR_OTHER; goto done; } if (!msg2->dn) { msg2->dn = msg->dn; } for (i=0; i<msg->num_elements; i++) { struct ldb_message_element *el = &msg->elements[i], *el2; struct ldb_val *vals; const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name); const char *dn; switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) { case LDB_FLAG_MOD_ADD: if (el->num_values == 0) { ldb_asprintf_errstring(ldb, "attribute '%s': attribute on '%s' specified, but with 0 values (illegal)", el->name, ldb_dn_get_linearized(msg2->dn)); ret = LDB_ERR_CONSTRAINT_VIOLATION; goto done; } /* make a copy of the array so that a permissive * control can remove duplicates without changing the * original values, but do not copy data as we do not * need to keep it around once the operation is * finished */ if (control_permissive) { el = talloc(msg2, struct ldb_message_element); if (!el) { ret = LDB_ERR_OTHER; goto done; } *el = msg->elements[i]; el->values = talloc_array(el, struct ldb_val, el->num_values); if (el->values == NULL) { ret = LDB_ERR_OTHER; goto done; } for (j = 0; j < el->num_values; j++) { el->values[j] = msg->elements[i].values[j]; } } if (el->num_values > 1 && ldb_tdb_single_valued(a, el)) { ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once", el->name, ldb_dn_get_linearized(msg2->dn)); ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; goto done; } /* Checks if element already exists */ idx = find_element(msg2, el->name); if (idx == -1) { if (ltdb_msg_add_element(ldb, msg2, el) != 0) { ret = LDB_ERR_OTHER; goto done; } ret = ltdb_index_add_element(module, msg2->dn, el); if (ret != LDB_SUCCESS) { goto done; } } else { j = (unsigned int) idx; el2 = &(msg2->elements[j]); /* We cannot add another value on a existing one if the attribute is single-valued */ if (ldb_tdb_single_valued(a, el)) { ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once", el->name, ldb_dn_get_linearized(msg2->dn)); ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; goto done; } /* Check that values don't exist yet on multi- valued attributes or aren't provided twice */ /* TODO: This is O(n^2) - replace with more efficient check */ for (j = 0; j < el->num_values; j++) { if (ldb_msg_find_val(el2, &el->values[j]) != NULL) { if (control_permissive) { /* remove this one as if it was never added */ el->num_values--; for (k = j; k < el->num_values; k++) { el->values[k] = el->values[k + 1]; } j--; /* rewind */ continue; } ldb_asprintf_errstring(ldb, "attribute '%s': value #%u on '%s' already exists", el->name, j, ldb_dn_get_linearized(msg2->dn)); ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; goto done; } if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) { ldb_asprintf_errstring(ldb, "attribute '%s': value #%u on '%s' provided more than once", el->name, j, ldb_dn_get_linearized(msg2->dn)); ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; goto done; } } /* Now combine existing and new values to a new attribute record */ vals = talloc_realloc(msg2->elements, el2->values, struct ldb_val, el2->num_values + el->num_values); if (vals == NULL) { ldb_oom(ldb); ret = LDB_ERR_OTHER; goto done; } for (j=0; j<el->num_values; j++) { vals[el2->num_values + j] = ldb_val_dup(vals, &el->values[j]); } el2->values = vals; el2->num_values += el->num_values; ret = ltdb_index_add_element(module, msg2->dn, el); if (ret != LDB_SUCCESS) { goto done; } } break; case LDB_FLAG_MOD_REPLACE: if (el->num_values > 1 && ldb_tdb_single_valued(a, el)) { ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once", el->name, ldb_dn_get_linearized(msg2->dn)); ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; goto done; } /* TODO: This is O(n^2) - replace with more efficient check */ for (j=0; j<el->num_values; j++) { if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) { ldb_asprintf_errstring(ldb, "attribute '%s': value #%u on '%s' provided more than once", el->name, j, ldb_dn_get_linearized(msg2->dn)); ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; goto done; } } /* Checks if element already exists */ idx = find_element(msg2, el->name); if (idx != -1) { j = (unsigned int) idx; el2 = &(msg2->elements[j]); /* we consider two elements to be * equal only if the order * matches. This allows dbcheck to * fix the ordering on attributes * where order matters, such as * objectClass */ if (ldb_msg_element_equal_ordered(el, el2)) { continue; } /* Delete the attribute if it exists in the DB */ if (msg_delete_attribute(module, ldb, msg2, el->name) != 0) { ret = LDB_ERR_OTHER; goto done; } } /* Recreate it with the new values */ if (ltdb_msg_add_element(ldb, msg2, el) != 0) { ret = LDB_ERR_OTHER; goto done; } ret = ltdb_index_add_element(module, msg2->dn, el); if (ret != LDB_SUCCESS) { goto done; } break; case LDB_FLAG_MOD_DELETE: dn = ldb_dn_get_linearized(msg2->dn); if (dn == NULL) { ret = LDB_ERR_OTHER; goto done; } if (msg->elements[i].num_values == 0) { /* Delete the whole attribute */ ret = msg_delete_attribute(module, ldb, msg2, msg->elements[i].name); if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && control_permissive) { ret = LDB_SUCCESS; } else { ldb_asprintf_errstring(ldb, "attribute '%s': no such attribute for delete on '%s'", msg->elements[i].name, dn); } if (ret != LDB_SUCCESS) { goto done; } } else { /* Delete specified values from an attribute */ for (j=0; j < msg->elements[i].num_values; j++) { ret = msg_delete_element(module, msg2, msg->elements[i].name, &msg->elements[i].values[j]); if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && control_permissive) { ret = LDB_SUCCESS; } else { ldb_asprintf_errstring(ldb, "attribute '%s': no matching attribute value while deleting attribute on '%s'", msg->elements[i].name, dn); } if (ret != LDB_SUCCESS) { goto done; } } } break; default: ldb_asprintf_errstring(ldb, "attribute '%s': invalid modify flags on '%s': 0x%x", msg->elements[i].name, ldb_dn_get_linearized(msg->dn), msg->elements[i].flags & LDB_FLAG_MOD_MASK); ret = LDB_ERR_PROTOCOL_ERROR; goto done; } } ret = ltdb_store(module, msg2, TDB_MODIFY); if (ret != LDB_SUCCESS) { goto done; } ret = ltdb_modified(module, msg2->dn); if (ret != LDB_SUCCESS) { goto done; } done: talloc_free(tdb_key.dptr); return ret; }
static int ltdb_add_internal(struct ldb_module *module, const struct ldb_message *msg, bool check_single_value) { struct ldb_context *ldb = ldb_module_get_ctx(module); int ret = LDB_SUCCESS; unsigned int i, j; for (i=0;i<msg->num_elements;i++) { struct ldb_message_element *el = &msg->elements[i]; const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name); if (el->num_values == 0) { ldb_asprintf_errstring(ldb, "attribute '%s' on '%s' specified, but with 0 values (illegal)", el->name, ldb_dn_get_linearized(msg->dn)); return LDB_ERR_CONSTRAINT_VIOLATION; } if (check_single_value && el->num_values > 1 && ldb_tdb_single_valued(a, el)) { ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once", el->name, ldb_dn_get_linearized(msg->dn)); return LDB_ERR_CONSTRAINT_VIOLATION; } /* Do not check "@ATTRIBUTES" for duplicated values */ if (ldb_dn_is_special(msg->dn) && ldb_dn_check_special(msg->dn, LTDB_ATTRIBUTES)) { continue; } /* TODO: This is O(n^2) - replace with more efficient check */ for (j=0; j<el->num_values; j++) { if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) { ldb_asprintf_errstring(ldb, "attribute '%s': value #%u on '%s' provided more than once", el->name, j, ldb_dn_get_linearized(msg->dn)); return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; } } } ret = ltdb_store(module, msg, TDB_INSERT); if (ret != LDB_SUCCESS) { if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) { ldb_asprintf_errstring(ldb, "Entry %s already exists", ldb_dn_get_linearized(msg->dn)); } return ret; } ret = ltdb_index_add_new(module, msg); if (ret != LDB_SUCCESS) { return ret; } ret = ltdb_modified(module, msg->dn); return ret; }
/* connect to the database */ static int ltdb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[], struct ldb_module **_module) { struct ldb_module *module; const char *path; int tdb_flags, open_flags; struct ltdb_private *ltdb; /* parse the url */ if (strchr(url, ':')) { if (strncmp(url, "tdb://", 6) != 0) { ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid tdb URL '%s'", url); return LDB_ERR_OPERATIONS_ERROR; } path = url+6; } else { path = url; } tdb_flags = TDB_DEFAULT | TDB_SEQNUM; /* check for the 'nosync' option */ if (flags & LDB_FLG_NOSYNC) { tdb_flags |= TDB_NOSYNC; } /* and nommap option */ if (flags & LDB_FLG_NOMMAP) { tdb_flags |= TDB_NOMMAP; } if (flags & LDB_FLG_RDONLY) { open_flags = O_RDONLY; } else { open_flags = O_CREAT | O_RDWR; } ltdb = talloc_zero(ldb, struct ltdb_private); if (!ltdb) { ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; } /* note that we use quite a large default hash size */ ltdb->tdb = ltdb_wrap_open(ltdb, path, 10000, tdb_flags, open_flags, ldb_get_create_perms(ldb), ldb); if (!ltdb->tdb) { ldb_asprintf_errstring(ldb, "Unable to open tdb '%s': %s", path, strerror(errno)); ldb_debug(ldb, LDB_DEBUG_ERROR, "Unable to open tdb '%s': %s", path, strerror(errno)); talloc_free(ltdb); if (errno == EACCES || errno == EPERM) { return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } return LDB_ERR_OPERATIONS_ERROR; } if (getenv("LDB_WARN_UNINDEXED")) { ltdb->warn_unindexed = true; } if (getenv("LDB_WARN_REINDEX")) { ltdb->warn_reindex = true; } ltdb->sequence_number = 0; module = ldb_module_new(ldb, ldb, "ldb_tdb backend", <db_ops); if (!module) { ldb_oom(ldb); talloc_free(ltdb); return LDB_ERR_OPERATIONS_ERROR; } ldb_module_set_private(module, ltdb); talloc_steal(module, ltdb); if (ltdb_cache_load(module) != 0) { ldb_asprintf_errstring(ldb, "Unable to load ltdb cache records of tdb '%s'", path); talloc_free(module); return LDB_ERR_OPERATIONS_ERROR; } *_module = module; return LDB_SUCCESS; }
static int ltdb_handle_request(struct ldb_module *module, struct ldb_request *req) { struct ldb_control *control_permissive; struct ldb_context *ldb; struct tevent_context *ev; struct ltdb_context *ac; struct tevent_timer *te; struct timeval tv; unsigned int i; ldb = ldb_module_get_ctx(module); control_permissive = ldb_request_get_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID); for (i = 0; req->controls && req->controls[i]; i++) { if (req->controls[i]->critical && req->controls[i] != control_permissive) { ldb_asprintf_errstring(ldb, "Unsupported critical extension %s", req->controls[i]->oid); return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; } } if (req->starttime == 0 || req->timeout == 0) { ldb_set_errstring(ldb, "Invalid timeout settings"); return LDB_ERR_TIME_LIMIT_EXCEEDED; } ev = ldb_get_event_context(ldb); ac = talloc_zero(ldb, struct ltdb_context); if (ac == NULL) { ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; } ac->module = module; ac->req = req; tv.tv_sec = 0; tv.tv_usec = 0; te = tevent_add_timer(ev, ac, tv, ltdb_callback, ac); if (NULL == te) { talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } if (req->timeout > 0) { tv.tv_sec = req->starttime + req->timeout; tv.tv_usec = 0; ac->timeout_event = tevent_add_timer(ev, ac, tv, ltdb_timeout, ac); if (NULL == ac->timeout_event) { talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } } /* set a spy so that we do not try to use the request context * if it is freed before ltdb_callback fires */ ac->spy = talloc(req, struct ltdb_req_spy); if (NULL == ac->spy) { talloc_free(ac); return LDB_ERR_OPERATIONS_ERROR; } ac->spy->ctx = ac; talloc_set_destructor((TALLOC_CTX *)ac->spy, ltdb_request_destructor); return LDB_SUCCESS; }
/* rename a record */ static int ltdb_rename(struct ltdb_context *ctx) { struct ldb_module *module = ctx->module; void *data = ldb_module_get_private(module); struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private); struct ldb_request *req = ctx->req; struct ldb_message *msg; int ret = LDB_SUCCESS; TDB_DATA tdb_key, tdb_key_old; ldb_request_set_state(req, LDB_ASYNC_PENDING); if (ltdb_cache_load(ctx->module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } msg = ldb_msg_new(ctx); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } /* we need to fetch the old record to re-add under the new name */ ret = ltdb_search_dn1(module, req->op.rename.olddn, msg); if (ret != LDB_SUCCESS) { /* not finding the old record is an error */ return ret; } /* We need to, before changing the DB, check if the new DN * exists, so we can return this error to the caller with an * unmodified DB */ tdb_key = ltdb_key(module, req->op.rename.newdn); if (!tdb_key.dptr) { talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; } tdb_key_old = ltdb_key(module, req->op.rename.olddn); if (!tdb_key_old.dptr) { talloc_free(msg); talloc_free(tdb_key.dptr); return LDB_ERR_OPERATIONS_ERROR; } /* Only declare a conflict if the new DN already exists, and it isn't a case change on the old DN */ if (tdb_key_old.dsize != tdb_key.dsize || memcmp(tdb_key.dptr, tdb_key_old.dptr, tdb_key.dsize) != 0) { if (tdb_exists(ltdb->tdb, tdb_key)) { talloc_free(tdb_key_old.dptr); talloc_free(tdb_key.dptr); ldb_asprintf_errstring(ldb_module_get_ctx(module), "Entry %s already exists", ldb_dn_get_linearized(msg->dn)); /* finding the new record already in the DB is an error */ talloc_free(msg); return LDB_ERR_ENTRY_ALREADY_EXISTS; } } talloc_free(tdb_key_old.dptr); talloc_free(tdb_key.dptr); /* Always delete first then add, to avoid conflicts with * unique indexes. We rely on the transaction to make this * atomic */ ret = ltdb_delete_internal(module, msg->dn); if (ret != LDB_SUCCESS) { talloc_free(msg); return ret; } msg->dn = ldb_dn_copy(msg, req->op.rename.newdn); if (msg->dn == NULL) { talloc_free(msg); return LDB_ERR_OPERATIONS_ERROR; } /* We don't check single value as we can have more than 1 with * deleted attributes. We could go through all elements but that's * maybe not the most efficient way */ ret = ltdb_add_internal(module, msg, false); talloc_free(msg); return ret; }
/* search for attrs on one DN, in the modules below */ int dsdb_module_search_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_result **_res, struct ldb_dn *basedn, const char * const *attrs, uint32_t dsdb_flags, struct ldb_request *parent) { int ret; struct ldb_request *req; TALLOC_CTX *tmp_ctx; struct ldb_result *res; tmp_ctx = talloc_new(mem_ctx); res = talloc_zero(tmp_ctx, struct ldb_result); if (!res) { talloc_free(tmp_ctx); return ldb_oom(ldb_module_get_ctx(module)); } ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx, basedn, LDB_SCOPE_BASE, NULL, attrs, NULL, res, ldb_search_default_callback, parent); LDB_REQ_SET_LOCATION(req); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } ret = dsdb_request_add_controls(req, dsdb_flags); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } if (dsdb_flags & DSDB_FLAG_TRUSTED) { ldb_req_mark_trusted(req); } /* Run the new request */ if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) { ret = ldb_next_request(module, req); } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) { ret = ldb_request(ldb_module_get_ctx(module), req); } else { const struct ldb_module_ops *ops = ldb_module_get_ops(module); SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE); ret = ops->search(module, req); } if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); } if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } if (res->count != 1) { /* we may be reading a DB that does not have the 'check base on search' option... */ ret = LDB_ERR_NO_SUCH_OBJECT; ldb_asprintf_errstring(ldb_module_get_ctx(module), "dsdb_module_search_dn: did not find base dn %s (%d results)", ldb_dn_get_linearized(basedn), res->count); } else { *_res = talloc_steal(mem_ctx, res); } talloc_free(tmp_ctx); return ret; }
static int samldb_fill_foreignSecurityPrincipal_object(struct ldb_module *module, const struct ldb_message *msg, struct ldb_message **ret_msg) { struct ldb_message *msg2; const char *rdn_name; struct dom_sid *dom_sid; struct dom_sid *sid; const char *dom_attrs[] = { "name", NULL }; struct ldb_message **dom_msgs; const char *errstr; int ret; TALLOC_CTX *mem_ctx = talloc_new(msg); if (!mem_ctx) { return LDB_ERR_OPERATIONS_ERROR; } /* build the new msg */ msg2 = ldb_msg_copy(mem_ctx, msg); if (!msg2) { ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincpal_object: ldb_msg_copy failed!\n"); talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } ret = samdb_copy_template(module->ldb, msg2, "(&(CN=TemplateForeignSecurityPrincipal)(objectclass=foreignSecurityPrincipalTemplate))", &errstr); if (ret != 0) { ldb_asprintf_errstring(module->ldb, "samldb_fill_foreignSecurityPrincipal_object: " "Error copying template: %s", errstr); talloc_free(mem_ctx); return ret; } rdn_name = ldb_dn_get_rdn_name(msg2->dn); if (strcasecmp(rdn_name, "cn") != 0) { ldb_asprintf_errstring(module->ldb, "Bad RDN (%s=) for ForeignSecurityPrincipal, should be CN=!", rdn_name); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } /* Slightly different for the foreign sids. We don't want * domain SIDs ending up there, it would cause all sorts of * pain */ sid = dom_sid_parse_talloc(msg2, (const char *)ldb_dn_get_rdn_val(msg2->dn)->data); if (!sid) { ldb_set_errstring(module->ldb, "No valid found SID in ForeignSecurityPrincipal CN!"); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) { talloc_free(sid); return LDB_ERR_OPERATIONS_ERROR; } dom_sid = dom_sid_dup(mem_ctx, sid); if (!dom_sid) { talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } /* get the domain component part of the provided SID */ dom_sid->num_auths--; /* find the domain DN */ ret = gendb_search(module->ldb, mem_ctx, NULL, &dom_msgs, dom_attrs, "(&(objectSid=%s)(objectclass=domain))", ldap_encode_ndr_dom_sid(mem_ctx, dom_sid)); if (ret >= 1) { /* We don't really like the idea of foreign sids that are not foreign, but it happens */ const char *name = samdb_result_string(dom_msgs[0], "name", NULL); ldb_debug(module->ldb, LDB_DEBUG_TRACE, "NOTE (strange but valid): Adding foreign SID record with SID %s, but this domian (%s) is already in the database", dom_sid_string(mem_ctx, sid), name); } else if (ret == -1) { ldb_asprintf_errstring(module->ldb, "samldb_fill_foreignSecurityPrincipal_object: error searching for a domain with this sid: %s\n", dom_sid_string(mem_ctx, dom_sid)); talloc_free(dom_msgs); return LDB_ERR_OPERATIONS_ERROR; } /* This isn't an operation on a domain we know about, so just * check for the SID, looking for duplicates via the common * code */ ret = samldb_notice_sid(module, msg2, sid); if (ret == 0) { talloc_steal(msg, msg2); *ret_msg = msg2; } return ret; }
static int samldb_fill_user_or_computer_object(struct ldb_module *module, const struct ldb_message *msg, struct ldb_message **ret_msg) { int ret; char *name; struct ldb_message *msg2; const char *rdn_name; TALLOC_CTX *mem_ctx = talloc_new(msg); const char *errstr; if (!mem_ctx) { return LDB_ERR_OPERATIONS_ERROR; } /* build the new msg */ msg2 = ldb_msg_copy(mem_ctx, msg); if (!msg2) { ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n"); talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } if (samdb_find_attribute(module->ldb, msg, "objectclass", "computer") != NULL) { ret = samdb_copy_template(module->ldb, msg2, "(&(CN=TemplateComputer)(objectclass=userTemplate))", &errstr); if (ret) { ldb_asprintf_errstring(module->ldb, "samldb_fill_user_or_computer_object: " "Error copying computer template: %s", errstr); talloc_free(mem_ctx); return ret; } /* readd user and then computer objectclasses */ ret = samdb_find_or_add_value(module->ldb, msg2, "objectclass", "user"); if (ret) { talloc_free(mem_ctx); return ret; } ret = samdb_find_or_add_value(module->ldb, msg2, "objectclass", "computer"); if (ret) { talloc_free(mem_ctx); return ret; } } else { ret = samdb_copy_template(module->ldb, msg2, "(&(CN=TemplateUser)(objectclass=userTemplate))", &errstr); if (ret) { ldb_asprintf_errstring(module->ldb, "samldb_fill_user_or_computer_object: Error copying user template: %s\n", errstr); talloc_free(mem_ctx); return ret; } /* readd user objectclass */ ret = samdb_find_or_add_value(module->ldb, msg2, "objectclass", "user"); if (ret) { talloc_free(mem_ctx); return ret; } } rdn_name = ldb_dn_get_rdn_name(msg2->dn); if (strcasecmp(rdn_name, "cn") != 0) { ldb_asprintf_errstring(module->ldb, "Bad RDN (%s=) for user/computer, should be CN=!\n", rdn_name); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } if (ldb_msg_find_element(msg2, "samAccountName") == NULL) { name = samldb_generate_samAccountName(module, mem_ctx); if (!name) { talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } ret = samdb_find_or_add_attribute(module->ldb, msg2, "sAMAccountName", name); if (ret) { talloc_free(mem_ctx); return ret; } } /* TODO: useraccountcontrol: setting value 0 gives 0x200 for users */ /* Manage SID allocation, conflicts etc */ ret = samldb_handle_sid(module, mem_ctx, msg2); /* TODO: objectCategory, userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */ if (ret == 0) { *ret_msg = msg2; talloc_steal(msg, msg2); } talloc_free(mem_ctx); return ret; }
int samldb_notice_sid(struct ldb_module *module, TALLOC_CTX *mem_ctx, const struct dom_sid *sid) { int ret; struct ldb_dn *dom_dn; struct dom_sid *dom_sid; const char *attrs[] = { NULL }; struct ldb_result *dom_res; struct ldb_result *res; uint32_t old_rid; /* find if this SID already exists */ ret = ldb_search_exp_fmt(module->ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs, "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, sid)); if (ret == LDB_SUCCESS) { if (res->count > 0) { talloc_free(res); ldb_asprintf_errstring(module->ldb, "Attempt to add record with SID %s rejected," " because this SID is already in the database", dom_sid_string(mem_ctx, sid)); /* We have a duplicate SID, we must reject the add */ return LDB_ERR_CONSTRAINT_VIOLATION; } talloc_free(res); } else { ldb_asprintf_errstring(module->ldb, "samldb_notice_sid: error searching to see if sid %s is in use: %s\n", dom_sid_string(mem_ctx, sid), ldb_errstring(module->ldb)); return ret; } dom_sid = dom_sid_dup(mem_ctx, sid); if (!dom_sid) { return LDB_ERR_OPERATIONS_ERROR; } /* get the domain component part of the provided SID */ dom_sid->num_auths--; /* find the domain DN */ ret = ldb_search_exp_fmt(module->ldb, mem_ctx, &dom_res, NULL, LDB_SCOPE_SUBTREE, attrs, "(&(objectSid=%s)(objectclass=domain))", ldap_encode_ndr_dom_sid(mem_ctx, dom_sid)); if (ret == LDB_SUCCESS) { if (dom_res->count == 0) { talloc_free(dom_res); /* This isn't an operation on a domain we know about, so nothing to update */ return LDB_SUCCESS; } if (dom_res->count > 1) { talloc_free(dom_res); ldb_asprintf_errstring(module->ldb, "samldb_notice_sid: error retrieving domain from sid: duplicate (found %d) domain: %s!\n", dom_res->count, dom_sid_string(dom_res, dom_sid)); return LDB_ERR_OPERATIONS_ERROR; } } else { ldb_asprintf_errstring(module->ldb, "samldb_notice_sid: error retrieving domain from sid: %s: %s\n", dom_sid_string(dom_res, dom_sid), ldb_errstring(module->ldb)); return ret; } dom_dn = dom_res->msgs[0]->dn; ret = samldb_find_next_rid(module, mem_ctx, dom_dn, &old_rid); if (ret) { talloc_free(dom_res); return ret; } if (old_rid <= sid->sub_auths[sid->num_auths - 1]) { ret = samldb_set_next_rid(module->ldb, mem_ctx, dom_dn, old_rid, sid->sub_auths[sid->num_auths - 1] + 1); } talloc_free(dom_res); return ret; }