/* return the attribute syntax oid as a string from the attribute name */ static PyObject *py_dsdb_get_syntax_oid_from_lDAPDisplayName(PyObject *self, PyObject *args) { PyObject *py_ldb; struct ldb_context *ldb; struct dsdb_schema *schema; const char *ldap_display_name; const struct dsdb_attribute *attribute; if (!PyArg_ParseTuple(args, "Os", &py_ldb, &ldap_display_name)) return NULL; PyErr_LDB_OR_RAISE(py_ldb, ldb); schema = dsdb_get_schema(ldb, NULL); if (!schema) { PyErr_SetString(PyExc_RuntimeError, "Failed to find a schema from ldb"); return NULL; } attribute = dsdb_attribute_by_lDAPDisplayName(schema, ldap_display_name); if (attribute == NULL) { PyErr_Format(PyExc_KeyError, "Failed to find attribute '%s'", ldap_display_name); return NULL; } return PyString_FromString(attribute->syntax->ldap_oid); }
static int validate_update_modify(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; struct dsdb_schema *schema; int ret; ldb = ldb_module_get_ctx(module); schema = dsdb_get_schema(ldb); if (!schema) { return ldb_next_request(module, req); } /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.mod.message->dn)) { return ldb_next_request(module, req); } ret = validate_update_message(ldb, schema, req->op.mod.message); if (ret != LDB_SUCCESS) { return ret; } return ldb_next_request(module, req); }
static PyObject *py_dsdb_set_schema_from_ldb(PyObject *self, PyObject *args) { PyObject *py_ldb; struct ldb_context *ldb; PyObject *py_from_ldb; struct ldb_context *from_ldb; struct dsdb_schema *schema; int ret; char write_indices_and_attributes = true; if (!PyArg_ParseTuple(args, "OO|b", &py_ldb, &py_from_ldb, &write_indices_and_attributes)) return NULL; PyErr_LDB_OR_RAISE(py_ldb, ldb); PyErr_LDB_OR_RAISE(py_from_ldb, from_ldb); schema = dsdb_get_schema(from_ldb, NULL); if (!schema) { PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on 'from' ldb!\n"); return NULL; } ret = dsdb_reference_schema(ldb, schema, write_indices_and_attributes); PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb); Py_RETURN_NONE; }
static PyObject *py_dsdb_get_lDAPDisplayName_by_attid(PyObject *self, PyObject *args) { PyObject *py_ldb; struct ldb_context *ldb; struct dsdb_schema *schema; const struct dsdb_attribute *a; uint32_t attid; if (!PyArg_ParseTuple(args, "Oi", &py_ldb, &attid)) return NULL; PyErr_LDB_OR_RAISE(py_ldb, ldb); schema = dsdb_get_schema(ldb, NULL); if (!schema) { PyErr_SetString(PyExc_RuntimeError, "Failed to find a schema from ldb"); return NULL; } a = dsdb_attribute_by_attributeID_id(schema, attid); if (a == NULL) { PyErr_Format(PyExc_KeyError, "Failed to find attribute '0x%08x'", attid); return NULL; } return PyString_FromString(a->lDAPDisplayName); }
static int construct_modifyTimeStamp(struct ldb_module *module, struct ldb_message *msg, enum ldb_scope scope, struct ldb_request *parent) { struct operational_data *data = talloc_get_type(ldb_module_get_private(module), struct operational_data); struct ldb_context *ldb = ldb_module_get_ctx(module); /* We may be being called before the init function has finished */ if (!data) { return LDB_SUCCESS; } /* Try and set this value up, if possible. Don't worry if it * fails, we may not have the DB set up yet. */ if (!data->aggregate_dn) { data->aggregate_dn = samdb_aggregate_schema_dn(ldb, data); } if (data->aggregate_dn && ldb_dn_compare(data->aggregate_dn, msg->dn) == 0) { /* * If we have the DN for the object with common name = Aggregate and * the request is for this DN then let's do the following: * 1) search the object which changedUSN correspond to the one of the loaded * schema. * 2) Get the whenChanged attribute * 3) Generate the modifyTimestamp out of the whenChanged attribute */ const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL); char *value = ldb_timestring(msg, schema->ts_last_change); return ldb_msg_add_string(msg, "modifyTimeStamp", value); } return ldb_msg_copy_attr(msg, "whenChanged", "modifyTimeStamp"); }
static int acl_childClasses(struct ldb_module *module, struct ldb_message *sd_msg, struct ldb_message *msg, const char *attrName) { struct ldb_message_element *oc_el; struct ldb_message_element *allowedClasses; struct ldb_context *ldb = ldb_module_get_ctx(module); const struct dsdb_schema *schema = dsdb_get_schema(ldb); const struct dsdb_class *sclass; int i, j, 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, or else confusion reins */ ldb_msg_remove_attr(msg, attrName); ret = ldb_msg_add_empty(msg, attrName, 0, &allowedClasses); if (ret != LDB_SUCCESS) { return ret; } oc_el = ldb_msg_find_element(sd_msg, "objectClass"); for (i=0; oc_el && i < oc_el->num_values; i++) { sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]); if (!sclass) { /* We don't know this class? what is going on? */ continue; } for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) { ldb_msg_add_string(msg, attrName, sclass->possibleInferiors[j]); } } if (allowedClasses->num_values > 1) { qsort(allowedClasses->values, allowedClasses->num_values, sizeof(*allowedClasses->values), (comparison_fn_t)data_blob_cmp); for (i=1 ; i < allowedClasses->num_values; i++) { struct ldb_val *val1 = &allowedClasses->values[i-1]; struct ldb_val *val2 = &allowedClasses->values[i]; if (data_blob_cmp(val1, val2) == 0) { memmove(val1, val2, (allowedClasses->num_values - i) * sizeof(struct ldb_val)); allowedClasses->num_values--; i--; } } } return LDB_SUCCESS; }
static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *in, struct ldb_val *out) { struct ldb_dn *dn1 = NULL; const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL); const struct dsdb_class *sclass; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); if (!tmp_ctx) { return LDB_ERR_OPERATIONS_ERROR; } if (!schema) { talloc_free(tmp_ctx); *out = data_blob_talloc(mem_ctx, in->data, in->length); if (in->data && !out->data) { return LDB_ERR_OPERATIONS_ERROR; } return LDB_SUCCESS; } dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in); if ( ! ldb_dn_validate(dn1)) { const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length); sclass = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName); if (sclass) { struct ldb_dn *dn = ldb_dn_new(tmp_ctx, ldb, sclass->defaultObjectCategory); if (dn == NULL) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn)); talloc_free(tmp_ctx); if (!out->data) { return LDB_ERR_OPERATIONS_ERROR; } return LDB_SUCCESS; } else { *out = data_blob_talloc(mem_ctx, in->data, in->length); talloc_free(tmp_ctx); if (in->data && !out->data) { return LDB_ERR_OPERATIONS_ERROR; } return LDB_SUCCESS; } } *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1)); talloc_free(tmp_ctx); if (!out->data) { return LDB_ERR_OPERATIONS_ERROR; } return LDB_SUCCESS; }
static const struct GUID *get_oc_guid_from_message(struct ldb_module *module, struct ldb_message *msg) { struct ldb_message_element *oc_el; struct ldb_context *ldb = ldb_module_get_ctx(module); oc_el = ldb_msg_find_element(msg, "objectClass"); if (!oc_el) { return NULL; } return class_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb), (char *)oc_el->values[oc_el->num_values-1].data); }
static int acl_check_access_on_class(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct security_descriptor *sd, struct dom_sid *rp_sid, uint32_t access, const char *class_name) { int ret; struct ldb_context *ldb = ldb_module_get_ctx(module); NTSTATUS status; uint32_t access_granted; struct object_tree *root = NULL; struct object_tree *new_node = NULL; struct GUID *guid; const struct dsdb_schema *schema = dsdb_get_schema(ldb); TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); struct security_token *token = acl_user_token(module); if (class_name) { guid = class_schemaid_guid_by_lDAPDisplayName(schema, class_name); if (!guid) { DEBUG(10, ("acl_search: cannot find class %s\n", class_name)); goto fail; } if (!insert_in_object_tree(tmp_ctx, guid, access, &root, &new_node)) { DEBUG(10, ("acl_search: cannot add to object tree guid\n")); goto fail; } } status = sec_access_check_ds(sd, token, access, &access_granted, root, rp_sid); if (!NT_STATUS_IS_OK(status)) { ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } else { ret = LDB_SUCCESS; } return ret; fail: return LDB_ERR_OPERATIONS_ERROR; }
static int acl_add(struct ldb_module *module, struct ldb_request *req) { int ret; struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.add.message->dn); struct ldb_context *ldb; struct ldb_message_element *oc_el; const struct GUID *guid; struct object_tree *root = NULL; struct object_tree *new_node = NULL; if (what_is_user(module) == SECURITY_SYSTEM) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.add.message->dn)) { return ldb_next_request(module, req); } ldb = ldb_module_get_ctx(module); /* Creating an NC. There is probably something we should do here, * but we will establish that later */ if ((ldb_dn_compare(req->op.add.message->dn, (ldb_get_schema_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.add.message->dn, (ldb_get_config_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.add.message->dn, (ldb_get_root_basedn(ldb))) == 0)) { return ldb_next_request(module, req); } oc_el = ldb_msg_find_element(req->op.add.message, "objectClass"); if (!oc_el || oc_el->num_values == 0) { DEBUG(10,("acl:operation error %s\n", ldb_dn_get_linearized(req->op.add.message->dn))); return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); } guid = class_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb), (char *)oc_el->values[oc_el->num_values-1].data); if (!insert_in_object_tree(req, guid, SEC_ADS_CREATE_CHILD, &root, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; } ret = check_access_on_dn(module, req, parent, SEC_ADS_CREATE_CHILD, root); if (ret != LDB_SUCCESS) { return ret; } return ldb_next_request(module, req); }
void dsdb_make_schema_global(struct ldb_context *ldb) { struct dsdb_schema *schema = dsdb_get_schema(ldb); if (!schema) { return; } if (global_schema) { talloc_unlink(talloc_autofree_context(), global_schema); } /* we want the schema to be around permanently */ talloc_reparent(talloc_parent(schema), talloc_autofree_context(), schema); global_schema = schema; dsdb_set_global_schema(ldb); }
static PyObject *py_dsdb_get_oid_from_attid(PyObject *self, PyObject *args) { PyObject *py_ldb; struct ldb_context *ldb; uint32_t attid; struct dsdb_schema *schema; const char *oid; PyObject *ret; WERROR status; TALLOC_CTX *mem_ctx; if (!PyArg_ParseTuple(args, "Oi", &py_ldb, &attid)) return NULL; PyErr_LDB_OR_RAISE(py_ldb, ldb); mem_ctx = talloc_new(NULL); if (!mem_ctx) { PyErr_NoMemory(); return NULL; } schema = dsdb_get_schema(ldb, mem_ctx); if (!schema) { PyErr_SetString(PyExc_RuntimeError, "Failed to find a schema from ldb \n"); talloc_free(mem_ctx); return NULL; } status = dsdb_schema_pfm_oid_from_attid(schema->prefixmap, attid, mem_ctx, &oid); if (!W_ERROR_IS_OK(status)) { PyErr_SetWERROR(status); talloc_free(mem_ctx); return NULL; } ret = PyString_FromString(oid); talloc_free(mem_ctx); return ret; }
static PyObject *py_dsdb_get_attid_from_lDAPDisplayName(PyObject *self, PyObject *args) { PyObject *py_ldb, *is_schema_nc; struct ldb_context *ldb; struct dsdb_schema *schema; const char *ldap_display_name; bool schema_nc = false; const struct dsdb_attribute *a; uint32_t attid; if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &ldap_display_name, &is_schema_nc)) return NULL; PyErr_LDB_OR_RAISE(py_ldb, ldb); if (is_schema_nc) { if (!PyBool_Check(is_schema_nc)) { PyErr_SetString(PyExc_TypeError, "Expected boolean is_schema_nc"); return NULL; } if (is_schema_nc == Py_True) { schema_nc = true; } } schema = dsdb_get_schema(ldb, NULL); if (!schema) { PyErr_SetString(PyExc_RuntimeError, "Failed to find a schema from ldb"); return NULL; } a = dsdb_attribute_by_lDAPDisplayName(schema, ldap_display_name); if (a == NULL) { PyErr_Format(PyExc_KeyError, "Failed to find attribute '%s'", ldap_display_name); return NULL; } attid = dsdb_attribute_get_attid(a, schema_nc); return PyLong_FromUnsignedLong(attid); }
/* * DSDB-SYNTAX fixture setup/teardown handlers implementation */ static bool torture_dsdb_syntax_tcase_setup(struct torture_context *tctx, void **data) { struct torture_dsdb_syntax *priv; priv = talloc_zero(tctx, struct torture_dsdb_syntax); torture_assert(tctx, priv, "No memory"); priv->ldb = provision_get_schema(priv, tctx->lp_ctx, NULL, NULL); torture_assert(tctx, priv->ldb, "Failed to load schema from disk"); priv->schema = dsdb_get_schema(priv->ldb, NULL); torture_assert(tctx, priv->schema, "Failed to fetch schema"); /* add 'authOrig' attribute with OR-Name syntax to schema */ if (!torture_syntax_add_OR_Name(tctx, priv->ldb, priv->schema)) { return false; } *data = priv; return true; }
/* return the backlink attribute name (if any) for an attribute */ static PyObject *py_dsdb_get_backlink_from_lDAPDisplayName(PyObject *self, PyObject *args) { PyObject *py_ldb; struct ldb_context *ldb; struct dsdb_schema *schema; const char *ldap_display_name; const struct dsdb_attribute *attribute, *target_attr; if (!PyArg_ParseTuple(args, "Os", &py_ldb, &ldap_display_name)) return NULL; PyErr_LDB_OR_RAISE(py_ldb, ldb); schema = dsdb_get_schema(ldb, NULL); if (!schema) { PyErr_SetString(PyExc_RuntimeError, "Failed to find a schema from ldb"); return NULL; } attribute = dsdb_attribute_by_lDAPDisplayName(schema, ldap_display_name); if (attribute == NULL) { PyErr_Format(PyExc_KeyError, "Failed to find attribute '%s'", ldap_display_name); return NULL; } if (attribute->linkID == 0) { Py_RETURN_NONE; } target_attr = dsdb_attribute_by_linkID(schema, attribute->linkID ^ 1); if (target_attr == NULL) { /* when we add pseudo-backlinks we'll need to handle them here */ Py_RETURN_NONE; } return PyString_FromString(target_attr->lDAPDisplayName); }
static PyObject *py_dsdb_write_prefixes_from_schema_to_ldb(PyObject *self, PyObject *args) { PyObject *py_ldb; struct ldb_context *ldb; WERROR result; struct dsdb_schema *schema; if (!PyArg_ParseTuple(args, "O", &py_ldb)) return NULL; PyErr_LDB_OR_RAISE(py_ldb, ldb); schema = dsdb_get_schema(ldb, NULL); if (!schema) { PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on ldb!\n"); return NULL; } result = dsdb_write_prefixes_from_schema_to_ldb(NULL, ldb, schema); PyErr_WERROR_NOT_OK_RAISE(result); Py_RETURN_NONE; }
bool torture_net_become_dc(struct torture_context *torture) { bool ret = true; NTSTATUS status; struct libnet_BecomeDC b; struct libnet_UnbecomeDC u; struct libnet_vampire_cb_state *s; struct ldb_message *msg; int ldb_ret; uint32_t i; char *private_dir; const char *address; struct nbt_name name; const char *netbios_name; struct cli_credentials *machine_account; struct test_join *tj; struct loadparm_context *lp_ctx; struct ldb_context *ldb; struct libnet_context *ctx; struct dsdb_schema *schema; char *location = NULL; torture_assert_ntstatus_ok(torture, torture_temp_dir(torture, "libnet_BecomeDC", &location), "torture_temp_dir should return NT_STATUS_OK" ); netbios_name = lpcfg_parm_string(torture->lp_ctx, NULL, "become dc", "smbtorture dc"); if (!netbios_name || !netbios_name[0]) { netbios_name = "smbtorturedc"; } make_nbt_name_server(&name, torture_setting_string(torture, "host", NULL)); /* do an initial name resolution to find its IP */ status = resolve_name_ex(lpcfg_resolve_context(torture->lp_ctx), 0, 0, &name, torture, &address, torture->ev); torture_assert_ntstatus_ok(torture, status, talloc_asprintf(torture, "Failed to resolve %s - %s\n", name.name, nt_errstr(status))); /* Join domain as a member server. */ tj = torture_join_domain(torture, netbios_name, ACB_WSTRUST, &machine_account); torture_assert(torture, tj, talloc_asprintf(torture, "%s failed to join domain as workstation\n", netbios_name)); s = libnet_vampire_cb_state_init(torture, torture->lp_ctx, torture->ev, netbios_name, torture_join_dom_netbios_name(tj), torture_join_dom_dns_name(tj), location); torture_assert(torture, s, "libnet_vampire_cb_state_init"); ctx = libnet_context_init(torture->ev, torture->lp_ctx); ctx->cred = cmdline_credentials; ZERO_STRUCT(b); b.in.domain_dns_name = torture_join_dom_dns_name(tj); b.in.domain_netbios_name = torture_join_dom_netbios_name(tj); b.in.domain_sid = torture_join_sid(tj); b.in.source_dsa_address = address; b.in.dest_dsa_netbios_name = netbios_name; b.in.callbacks.private_data = s; b.in.callbacks.check_options = libnet_vampire_cb_check_options; b.in.callbacks.prepare_db = libnet_vampire_cb_prepare_db; b.in.callbacks.schema_chunk = libnet_vampire_cb_schema_chunk; b.in.callbacks.config_chunk = libnet_vampire_cb_store_chunk; b.in.callbacks.domain_chunk = libnet_vampire_cb_store_chunk; status = libnet_BecomeDC(ctx, s, &b); torture_assert_ntstatus_ok_goto(torture, status, ret, cleanup, talloc_asprintf(torture, "libnet_BecomeDC() failed - %s %s\n", nt_errstr(status), b.out.error_string)); ldb = libnet_vampire_cb_ldb(s); msg = ldb_msg_new(s); torture_assert_int_equal_goto(torture, (msg?1:0), 1, ret, cleanup, "ldb_msg_new() failed\n"); msg->dn = ldb_dn_new(msg, ldb, "@ROOTDSE"); torture_assert_int_equal_goto(torture, (msg->dn?1:0), 1, ret, cleanup, "ldb_msg_new(@ROOTDSE) failed\n"); ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE"); torture_assert_int_equal_goto(torture, ldb_ret, LDB_SUCCESS, ret, cleanup, "ldb_msg_add_string(msg, isSynchronized, TRUE) failed\n"); for (i=0; i < msg->num_elements; i++) { msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; } torture_comment(torture, "mark ROOTDSE with isSynchronized=TRUE\n"); ldb_ret = ldb_modify(libnet_vampire_cb_ldb(s), msg); torture_assert_int_equal_goto(torture, ldb_ret, LDB_SUCCESS, ret, cleanup, "ldb_modify() failed\n"); /* commit the transaction now we know the secrets were written * out properly */ ldb_ret = ldb_transaction_commit(ldb); torture_assert_int_equal_goto(torture, ldb_ret, LDB_SUCCESS, ret, cleanup, "ldb_transaction_commit() failed\n"); /* reopen the ldb */ talloc_unlink(s, ldb); lp_ctx = libnet_vampire_cb_lp_ctx(s); private_dir = talloc_asprintf(s, "%s/%s", location, "private"); lpcfg_set_cmdline(lp_ctx, "private dir", private_dir); torture_comment(torture, "Reopen the SAM LDB with system credentials and all replicated data: %s\n", private_dir); ldb = samdb_connect(s, torture->ev, lp_ctx, system_session(lp_ctx), 0); torture_assert_goto(torture, ldb != NULL, ret, cleanup, talloc_asprintf(torture, "Failed to open '%s/sam.ldb'\n", private_dir)); torture_assert_goto(torture, dsdb_uses_global_schema(ldb), ret, cleanup, "Uses global schema"); schema = dsdb_get_schema(ldb, s); torture_assert_goto(torture, schema != NULL, ret, cleanup, "Failed to get loaded dsdb_schema\n"); /* Make sure we get this from the command line */ if (lpcfg_parm_bool(torture->lp_ctx, NULL, "become dc", "do not unjoin", false)) { talloc_free(s); return ret; } cleanup: ZERO_STRUCT(u); u.in.domain_dns_name = torture_join_dom_dns_name(tj); u.in.domain_netbios_name = torture_join_dom_netbios_name(tj); u.in.source_dsa_address = address; u.in.dest_dsa_netbios_name = netbios_name; status = libnet_UnbecomeDC(ctx, s, &u); torture_assert_ntstatus_ok(torture, status, talloc_asprintf(torture, "libnet_UnbecomeDC() failed - %s %s\n", nt_errstr(status), u.out.error_string)); /* Leave domain. */ torture_leave_domain(torture, tj); talloc_free(s); return ret; }
static int acl_childClassesEffective(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_message_element *allowedClasses = NULL; struct ldb_context *ldb = ldb_module_get_ctx(module); const struct dsdb_schema *schema = dsdb_get_schema(ldb); const struct dsdb_class *sclass; struct security_descriptor *sd; struct dom_sid *sid = NULL; int i, j, ret; if (ac->user_type == SECURITY_SYSTEM) { return acl_childClasses(module, sd_msg, msg, "allowedChildClassesEffective"); } /* If we don't have a schema yet, we can't do anything... */ if (schema == NULL) { return LDB_SUCCESS; } /* Must remove any existing attribute, or else confusion reins */ ldb_msg_remove_attr(msg, "allowedChildClassesEffective"); oc_el = ldb_msg_find_element(sd_msg, "objectClass"); ret = get_sd_from_ldb_message(msg, sd_msg, &sd); if (ret != LDB_SUCCESS) { return ret; } ret = get_dom_sid_from_ldb_message(msg, sd_msg, &sid); if (ret != LDB_SUCCESS) { return ret; } for (i=0; oc_el && i < oc_el->num_values; i++) { sclass = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &oc_el->values[i]); if (!sclass) { /* We don't know this class? what is going on? */ continue; } for (j=0; sclass->possibleInferiors && sclass->possibleInferiors[j]; j++) { ret = acl_check_access_on_class(module, msg, sd, sid, SEC_ADS_CREATE_CHILD, sclass->possibleInferiors[j]); if (ret == LDB_SUCCESS) { ldb_msg_add_string(msg, "allowedChildClassesEffective", sclass->possibleInferiors[j]); } } } allowedClasses = ldb_msg_find_element(msg, "allowedChildClassesEffective"); if (!allowedClasses) { return LDB_SUCCESS; } if (allowedClasses->num_values > 1) { qsort(allowedClasses->values, allowedClasses->num_values, sizeof(*allowedClasses->values), (comparison_fn_t)data_blob_cmp); for (i=1 ; i < allowedClasses->num_values; i++) { struct ldb_val *val1 = &allowedClasses->values[i-1]; struct ldb_val *val2 = &allowedClasses->values[i]; if (data_blob_cmp(val1, val2) == 0) { memmove(val1, val2, (allowedClasses->num_values - i) * sizeof( struct ldb_val)); allowedClasses->num_values--; i--; } } } return LDB_SUCCESS; }
WERROR dsdb_origin_objects_commit(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct drsuapi_DsReplicaObjectListItem *first_object, uint32_t *_num, uint32_t dsdb_repl_flags, struct drsuapi_DsReplicaObjectIdentifier2 **_ids) { WERROR status; const struct dsdb_schema *schema; const struct drsuapi_DsReplicaObjectListItem *cur; struct ldb_message **objects; struct drsuapi_DsReplicaObjectIdentifier2 *ids; uint32_t i; uint32_t num_objects = 0; const char * const attrs[] = { "objectGUID", "objectSid", NULL }; struct ldb_result *res; int ret; for (cur = first_object; cur; cur = cur->next_object) { num_objects++; } if (num_objects == 0) { return WERR_OK; } ret = ldb_transaction_start(ldb); if (ret != LDB_SUCCESS) { return WERR_DS_INTERNAL_FAILURE; } objects = talloc_array(mem_ctx, struct ldb_message *, num_objects); if (objects == NULL) { status = WERR_NOMEM; goto cancel; } schema = dsdb_get_schema(ldb, objects); if (!schema) { return WERR_DS_SCHEMA_NOT_LOADED; } for (i=0, cur = first_object; cur; cur = cur->next_object, i++) { status = dsdb_origin_object_convert(ldb, schema, cur, objects, &objects[i]); if (!W_ERROR_IS_OK(status)) { goto cancel; } } ids = talloc_array(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier2, num_objects); if (ids == NULL) { status = WERR_NOMEM; goto cancel; } if (dsdb_repl_flags & DSDB_REPL_FLAG_ADD_NCNAME) { /* check for possible NC creation */ for (i=0; i < num_objects; i++) { struct ldb_message *msg = objects[i]; struct ldb_message_element *el; struct ldb_dn *nc_dn; if (ldb_msg_check_string_attribute(msg, "objectClass", "crossRef") == 0) { continue; } el = ldb_msg_find_element(msg, "nCName"); if (el == NULL || el->num_values != 1) { continue; } nc_dn = ldb_dn_from_ldb_val(objects, ldb, &el->values[0]); if (!ldb_dn_validate(nc_dn)) { continue; } ret = dsdb_create_partial_replica_NC(ldb, nc_dn); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } } } for (i=0; i < num_objects; i++) { struct dom_sid *sid = NULL; struct ldb_request *add_req; DEBUG(6,(__location__ ": adding %s\n", ldb_dn_get_linearized(objects[i]->dn))); ret = ldb_build_add_req(&add_req, ldb, objects, objects[i], NULL, NULL, ldb_op_default_callback, NULL); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ret = ldb_request(ldb, add_req); if (ret == LDB_SUCCESS) { ret = ldb_wait(add_req->handle, LDB_WAIT_ALL); } if (ret != LDB_SUCCESS) { DEBUG(0,(__location__ ": Failed add of %s - %s\n", ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb))); status = WERR_DS_INTERNAL_FAILURE; goto cancel; } talloc_free(add_req); ret = ldb_search(ldb, objects, &res, objects[i]->dn, LDB_SCOPE_BASE, attrs, "(objectClass=*)"); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID"); sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid"); if (sid) { ids[i].sid = *sid; } else { ZERO_STRUCT(ids[i].sid); } } ret = ldb_transaction_commit(ldb); if (ret != LDB_SUCCESS) { return WERR_DS_INTERNAL_FAILURE; } talloc_free(objects); *_num = num_objects; *_ids = ids; return WERR_OK; cancel: talloc_free(objects); ldb_transaction_cancel(ldb); return status; }
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; }
/** * Commits a list of replicated objects. * * @param working_schema dsdb_schema to be used for resolving * Classes/Attributes during Schema replication. If not NULL, * it will be set on ldb and used while committing replicated objects */ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb, struct dsdb_schema *working_schema, struct dsdb_extended_replicated_objects *objects, uint64_t *notify_uSN) { WERROR werr; struct ldb_result *ext_res; struct dsdb_schema *cur_schema = NULL; struct dsdb_schema *new_schema = NULL; int ret; uint64_t seq_num1, seq_num2; bool used_global_schema = false; TALLOC_CTX *tmp_ctx = talloc_new(objects); if (!tmp_ctx) { DEBUG(0,("Failed to start talloc\n")); return WERR_NOMEM; } /* TODO: handle linked attributes */ /* wrap the extended operation in a transaction See [MS-DRSR] 3.3.2 Transactions */ ret = ldb_transaction_start(ldb); if (ret != LDB_SUCCESS) { DEBUG(0,(__location__ " Failed to start transaction\n")); return WERR_FOOBAR; } ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num1, NULL); if (ret != LDB_SUCCESS) { DEBUG(0,(__location__ " Failed to load partition uSN\n")); ldb_transaction_cancel(ldb); TALLOC_FREE(tmp_ctx); return WERR_FOOBAR; } /* * Set working_schema for ldb in case we are replicating from Schema NC. * Schema won't be reloaded during Replicated Objects commit, as it is * done in a transaction. So we need some way to search for newly * added Classes and Attributes */ if (working_schema) { /* store current schema so we can fall back in case of failure */ cur_schema = dsdb_get_schema(ldb, tmp_ctx); used_global_schema = dsdb_uses_global_schema(ldb); ret = dsdb_reference_schema(ldb, working_schema, false); if (ret != LDB_SUCCESS) { DEBUG(0,(__location__ "Failed to reference working schema - %s\n", ldb_strerror(ret))); /* TODO: Map LDB Error to NTSTATUS? */ ldb_transaction_cancel(ldb); TALLOC_FREE(tmp_ctx); return WERR_INTERNAL_ERROR; } } ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, objects, &ext_res); if (ret != LDB_SUCCESS) { /* restore previous schema */ if (used_global_schema) { dsdb_set_global_schema(ldb); } else if (cur_schema) { dsdb_reference_schema(ldb, cur_schema, false); } DEBUG(0,("Failed to apply records: %s: %s\n", ldb_errstring(ldb), ldb_strerror(ret))); ldb_transaction_cancel(ldb); TALLOC_FREE(tmp_ctx); return WERR_FOOBAR; } talloc_free(ext_res); /* Save our updated prefixMap */ if (working_schema) { werr = dsdb_write_prefixes_from_schema_to_ldb(working_schema, ldb, working_schema); if (!W_ERROR_IS_OK(werr)) { /* restore previous schema */ if (used_global_schema) { dsdb_set_global_schema(ldb); } else if (cur_schema ) { dsdb_reference_schema(ldb, cur_schema, false); } DEBUG(0,("Failed to save updated prefixMap: %s\n", win_errstr(werr))); TALLOC_FREE(tmp_ctx); return werr; } } ret = ldb_transaction_prepare_commit(ldb); if (ret != LDB_SUCCESS) { /* restore previous schema */ if (used_global_schema) { dsdb_set_global_schema(ldb); } else if (cur_schema ) { dsdb_reference_schema(ldb, cur_schema, false); } DEBUG(0,(__location__ " Failed to prepare commit of transaction: %s\n", ldb_errstring(ldb))); TALLOC_FREE(tmp_ctx); return WERR_FOOBAR; } ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num2, NULL); if (ret != LDB_SUCCESS) { /* restore previous schema */ if (used_global_schema) { dsdb_set_global_schema(ldb); } else if (cur_schema ) { dsdb_reference_schema(ldb, cur_schema, false); } DEBUG(0,(__location__ " Failed to load partition uSN\n")); ldb_transaction_cancel(ldb); TALLOC_FREE(tmp_ctx); return WERR_FOOBAR; } ret = ldb_transaction_commit(ldb); if (ret != LDB_SUCCESS) { /* restore previous schema */ if (used_global_schema) { dsdb_set_global_schema(ldb); } else if (cur_schema ) { dsdb_reference_schema(ldb, cur_schema, false); } DEBUG(0,(__location__ " Failed to commit transaction\n")); TALLOC_FREE(tmp_ctx); return WERR_FOOBAR; } /* if this replication partner didn't need to be notified before this transaction then it still doesn't need to be notified, as the changes came from this server */ if (seq_num2 > seq_num1 && seq_num1 <= *notify_uSN) { *notify_uSN = seq_num2; } /* * Reset the Schema used by ldb. This will lead to * a schema cache being refreshed from database. */ if (working_schema) { struct ldb_message *msg; struct ldb_request *req; /* Force a reload */ working_schema->last_refresh = 0; new_schema = dsdb_get_schema(ldb, tmp_ctx); /* TODO: * If dsdb_get_schema() fails, we just fall back * to what we had. However, the database is probably * unable to operate for other users from this * point... */ if (new_schema && used_global_schema) { dsdb_make_schema_global(ldb, new_schema); } else if (used_global_schema) { DEBUG(0,("Failed to re-load schema after commit of transaction\n")); dsdb_set_global_schema(ldb); TALLOC_FREE(tmp_ctx); return WERR_INTERNAL_ERROR; } else { DEBUG(0,("Failed to re-load schema after commit of transaction\n")); dsdb_reference_schema(ldb, cur_schema, false); TALLOC_FREE(tmp_ctx); return WERR_INTERNAL_ERROR; } msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { TALLOC_FREE(tmp_ctx); return WERR_NOMEM; } msg->dn = ldb_dn_new(msg, ldb, ""); if (msg->dn == NULL) { TALLOC_FREE(tmp_ctx); return WERR_NOMEM; } ret = ldb_msg_add_string(msg, "schemaUpdateNow", "1"); if (ret != LDB_SUCCESS) { TALLOC_FREE(tmp_ctx); return WERR_INTERNAL_ERROR; } ret = ldb_build_mod_req(&req, ldb, objects, msg, NULL, NULL, ldb_op_default_callback, NULL); if (ret != LDB_SUCCESS) { TALLOC_FREE(tmp_ctx); return WERR_DS_DRA_INTERNAL_ERROR; } ret = ldb_transaction_start(ldb); if (ret != LDB_SUCCESS) { TALLOC_FREE(tmp_ctx); DEBUG(0, ("Autotransaction start failed\n")); return WERR_DS_DRA_INTERNAL_ERROR; } ret = ldb_request(ldb, req); if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); } if (ret == LDB_SUCCESS) { ret = ldb_transaction_commit(ldb); } else { DEBUG(0, ("Schema update now failed: %s\n", ldb_errstring(ldb))); ldb_transaction_cancel(ldb); } if (ret != LDB_SUCCESS) { DEBUG(0, ("Commit failed: %s\n", ldb_errstring(ldb))); TALLOC_FREE(tmp_ctx); return WERR_DS_INTERNAL_FAILURE; } } DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n", objects->num_objects, objects->linked_attributes_count, ldb_dn_get_linearized(objects->partition_dn))); TALLOC_FREE(tmp_ctx); return WERR_OK; }
/* normalise a ldb attribute list */ static PyObject *py_dsdb_normalise_attributes(PyObject *self, PyObject *args) { PyObject *py_ldb, *el_list, *py_ret; struct ldb_context *ldb; char *ldap_display_name; const struct dsdb_attribute *a; struct dsdb_schema *schema; struct dsdb_syntax_ctx syntax_ctx; struct ldb_message_element *el, *new_el; struct drsuapi_DsReplicaAttribute *attr; PyLdbMessageElementObject *ret; TALLOC_CTX *tmp_ctx; WERROR werr; Py_ssize_t i; PyTypeObject *py_type = NULL; PyObject *module = NULL; if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &ldap_display_name, &el_list)) { return NULL; } PyErr_LDB_OR_RAISE(py_ldb, ldb); schema = dsdb_get_schema(ldb, NULL); if (!schema) { PyErr_SetString(PyExc_RuntimeError, "Failed to find a schema from ldb"); return NULL; } a = dsdb_attribute_by_lDAPDisplayName(schema, ldap_display_name); if (a == NULL) { PyErr_Format(PyExc_KeyError, "Failed to find attribute '%s'", ldap_display_name); return NULL; } dsdb_syntax_ctx_init(&syntax_ctx, ldb, schema); syntax_ctx.is_schema_nc = false; tmp_ctx = talloc_new(ldb); if (tmp_ctx == NULL) { PyErr_NoMemory(); return NULL; } if (!PyList_Check(el_list)) { if (!py_check_dcerpc_type(el_list, "ldb", "MessageElement")) { PyErr_SetString(py_ldb_get_exception(), "list of strings or ldb MessageElement object required"); return NULL; } /* * NOTE: * el may not be a valid talloc context, it * could be part of an array */ el = pyldb_MessageElement_AsMessageElement(el_list); } else { el = talloc_zero(tmp_ctx, struct ldb_message_element); if (el == NULL) { PyErr_NoMemory(); talloc_free(tmp_ctx); return NULL; } el->name = ldap_display_name; el->num_values = PyList_Size(el_list); el->values = talloc_array(el, struct ldb_val, el->num_values); if (el->values == NULL) { PyErr_NoMemory(); talloc_free(tmp_ctx); return NULL; } for (i = 0; i < el->num_values; i++) { PyObject *item = PyList_GetItem(el_list, i); if (!PyString_Check(item)) { PyErr_Format(PyExc_TypeError, "ldif_elements should be strings"); talloc_free(tmp_ctx); return NULL; } el->values[i].data = (uint8_t *)PyString_AsString(item); el->values[i].length = PyString_Size(item); } } new_el = talloc_zero(tmp_ctx, struct ldb_message_element); if (new_el == NULL) { PyErr_NoMemory(); talloc_free(tmp_ctx); return NULL; } /* Normalise "objectClass" attribute if needed */ if (ldb_attr_cmp(a->lDAPDisplayName, "objectClass") == 0) { int iret; iret = dsdb_sort_objectClass_attr(ldb, schema, el, new_el, new_el); if (iret != LDB_SUCCESS) { PyErr_SetString(PyExc_RuntimeError, ldb_errstring(ldb)); talloc_free(tmp_ctx); return NULL; } } /* first run ldb_to_drsuapi, then convert back again. This has * the effect of normalising the attributes */ attr = talloc_zero(tmp_ctx, struct drsuapi_DsReplicaAttribute); if (attr == NULL) { PyErr_NoMemory(); talloc_free(tmp_ctx); return NULL; } werr = a->syntax->ldb_to_drsuapi(&syntax_ctx, a, el, attr, attr); PyErr_WERROR_NOT_OK_RAISE(werr); /* now convert back again */ werr = a->syntax->drsuapi_to_ldb(&syntax_ctx, a, attr, new_el, new_el); PyErr_WERROR_NOT_OK_RAISE(werr); module = PyImport_ImportModule("ldb"); if (module == NULL) { return NULL; } py_type = (PyTypeObject *)PyObject_GetAttrString(module, "MessageElement"); if (py_type == NULL) { return NULL; } py_ret = py_type->tp_alloc(py_type, 0); ret = (PyLdbMessageElementObject *)py_ret; ret->mem_ctx = talloc_new(NULL); if (talloc_reference(ret->mem_ctx, new_el) == NULL) { PyErr_NoMemory(); return NULL; } ret->el = new_el; talloc_free(tmp_ctx); return py_ret; }
/** * Loads dsdb_schema from ldb connection using remote prefixMap. * Schema will be loaded only if: * - ldb has no attached schema * - reload_schema is true * * This function is to be used in tests that use GetNCChanges() function */ bool drs_util_dsdb_schema_load_ldb(struct torture_context *tctx, struct ldb_context *ldb, const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr, bool reload_schema) { int i, ret; WERROR werr; const char *err_msg; struct ldb_result *a_res; struct ldb_result *c_res; struct ldb_dn *schema_dn; struct dsdb_schema *ldap_schema; ldap_schema = dsdb_get_schema(ldb, NULL); if (ldap_schema && !reload_schema) { return true; } schema_dn = ldb_get_schema_basedn(ldb); torture_assert(tctx, schema_dn != NULL, talloc_asprintf(tctx, "ldb_get_schema_basedn() failed: %s", ldb_errstring(ldb))); ldap_schema = dsdb_new_schema(ldb); torture_assert(tctx, ldap_schema != NULL, "dsdb_new_schema() failed!"); werr = dsdb_load_prefixmap_from_drsuapi(ldap_schema, mapping_ctr); torture_assert_werr_ok(tctx, werr, "Failed to construct prefixMap from drsuapi data"); /* * load the attribute definitions */ ret = ldb_search(ldb, ldap_schema, &a_res, schema_dn, LDB_SCOPE_ONELEVEL, NULL, "(objectClass=attributeSchema)"); if (ret != LDB_SUCCESS) { err_msg = talloc_asprintf(tctx, "failed to search attributeSchema objects: %s", ldb_errstring(ldb)); torture_fail(tctx, err_msg); } /* * load the objectClass definitions */ ret = ldb_search(ldb, ldap_schema, &c_res, schema_dn, LDB_SCOPE_ONELEVEL, NULL, "(objectClass=classSchema)"); if (ret != LDB_SUCCESS) { err_msg = talloc_asprintf(tctx, "failed to search classSchema objects: %s", ldb_errstring(ldb)); torture_fail(tctx, err_msg); } /* Build schema */ for (i=0; i < a_res->count; i++) { werr = dsdb_attribute_from_ldb(ldb, ldap_schema, a_res->msgs[i]); torture_assert_werr_ok(tctx, werr, talloc_asprintf(tctx, "dsdb_attribute_from_ldb() failed for: %s", ldb_dn_get_linearized(a_res->msgs[i]->dn))); } for (i=0; i < c_res->count; i++) { werr = dsdb_class_from_ldb(ldap_schema, c_res->msgs[i]); torture_assert_werr_ok(tctx, werr, talloc_asprintf(tctx, "dsdb_class_from_ldb() failed for: %s", ldb_dn_get_linearized(c_res->msgs[i]->dn))); } talloc_free(a_res); talloc_free(c_res); ret = dsdb_set_schema(ldb, ldap_schema); if (ret != LDB_SUCCESS) { torture_fail(tctx, talloc_asprintf(tctx, "dsdb_set_schema() failed: %s", ldb_strerror(ret))); } return true; }
/* get metadata version 2 info for a specified object DN */ static WERROR kccdrs_replica_get_info_obj_metadata2(TALLOC_CTX *mem_ctx, struct ldb_context *samdb, struct drsuapi_DsReplicaGetInfo *r, union drsuapi_DsReplicaInfo *reply, struct ldb_dn *dn, uint32_t base_index) { WERROR status; struct replPropertyMetaDataBlob omd_ctr; struct replPropertyMetaData1 *attr; struct drsuapi_DsReplicaObjMetaData2Ctr *metadata2; const struct dsdb_schema *schema; uint32_t i, j; DEBUG(0, ("kccdrs_replica_get_info_obj_metadata2() called\n")); if (!dn) { return WERR_INVALID_PARAMETER; } if (!ldb_dn_validate(dn)) { return WERR_DS_DRA_BAD_DN; } status = get_repl_prop_metadata_ctr(mem_ctx, samdb, dn, &omd_ctr); W_ERROR_NOT_OK_RETURN(status); schema = dsdb_get_schema(samdb, reply); if (!schema) { DEBUG(0,(__location__": Failed to get the schema\n")); return WERR_INTERNAL_ERROR; } reply->objmetadata2 = talloc_zero(mem_ctx, struct drsuapi_DsReplicaObjMetaData2Ctr); W_ERROR_HAVE_NO_MEMORY(reply->objmetadata2); metadata2 = reply->objmetadata2; metadata2->enumeration_context = 0; /* For each replicated attribute of the object */ for (i = 0, j = 0; i < omd_ctr.ctr.ctr1.count; i++) { const struct dsdb_attribute *schema_attr; uint32_t attr_version; NTTIME attr_change_time; uint32_t attr_originating_usn; /* attr := attrsSeq[i] s := AttrStamp(object, attr) */ /* get a reference to the attribute on 'omd_ctr' */ attr = &omd_ctr.ctr.ctr1.array[j]; schema_attr = dsdb_attribute_by_attributeID_id(schema, attr->attid); DEBUG(0, ("attribute_id = %d, attribute_name: %s\n", attr->attid, schema_attr->lDAPDisplayName)); /* if (attr in Link Attributes of object and dwInVersion = 2 and DS_REPL_INFO_FLAG_IMPROVE_LINKED_ATTRS in msgIn.ulFlags) */ if (schema_attr && schema_attr->linkID != 0 && /* Checks if attribute is a linked attribute */ (schema_attr->linkID % 2) == 0 && /* is it a forward link? only forward links have the LinkValueStamp */ r->in.level == 2 && (r->in.req->req2.flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)) /* on MS-DRSR it is DS_REPL_INFO_FLAG_IMPROVE_LINKED_ATTRS */ { /* ls := LinkValueStamp of the most recent value change in object!attr */ status = get_linked_attribute_value_stamp(mem_ctx, samdb, dn, schema_attr->lDAPDisplayName, &attr_version, &attr_change_time, &attr_originating_usn); W_ERROR_NOT_OK_RETURN(status); /* Aligning to MS-DRSR 4.1.13.3: 's' on the doc is 'attr->originating_change_time' here 'ls' on the doc is 'attr_change_time' here */ /* if (ls is more recent than s (based on order in which the change was applied on server)) then */ if (attr_change_time > attr->originating_change_time) { /* Improve the stamp with the link value stamp. s.dwVersion := ls.dwVersion s.timeChanged := ls.timeChanged s.uuidOriginating := NULLGUID s.usnOriginating := ls.usnOriginating */ attr->version = attr_version; attr->originating_change_time = attr_change_time; attr->originating_invocation_id = GUID_zero(); attr->originating_usn = attr_originating_usn; } } if (i < base_index) { continue; } metadata2->array = talloc_realloc(mem_ctx, metadata2->array, struct drsuapi_DsReplicaObjMetaData2, j + 1); W_ERROR_HAVE_NO_MEMORY(metadata2->array); metadata2->array[j].attribute_name = schema_attr->lDAPDisplayName; metadata2->array[j].local_usn = attr->local_usn; metadata2->array[j].originating_change_time = attr->originating_change_time; metadata2->array[j].originating_invocation_id = attr->originating_invocation_id; metadata2->array[j].originating_usn = attr->originating_usn; metadata2->array[j].version = attr->version; /* originating_dsa_dn := GetDNFromInvocationID(originating_invocation_id) GetDNFromInvocationID() should return the DN of the nTDSDSAobject that has the specified invocation ID See MS-DRSR 4.1.13.3 and 4.1.13.2.1 */ status = get_dn_from_invocation_id(mem_ctx, samdb, &attr->originating_invocation_id, &metadata2->array[j].originating_dsa_dn); W_ERROR_NOT_OK_RETURN(status); j++; metadata2->count = j; } return WERR_OK; }
WERROR dsdb_extended_replicated_objects_convert(struct ldb_context *ldb, const char *partition_dn, const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr, uint32_t object_count, const struct drsuapi_DsReplicaObjectListItemEx *first_object, uint32_t linked_attributes_count, const struct drsuapi_DsReplicaLinkedAttribute *linked_attributes, const struct repsFromTo1 *source_dsa, const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector, const DATA_BLOB *gensec_skey, TALLOC_CTX *mem_ctx, struct dsdb_extended_replicated_objects **objects) { WERROR status; const struct dsdb_schema *schema; struct dsdb_extended_replicated_objects *out; const struct drsuapi_DsReplicaObjectListItemEx *cur; uint32_t i; schema = dsdb_get_schema(ldb); if (!schema) { return WERR_DS_SCHEMA_NOT_LOADED; } status = dsdb_schema_pfm_contains_drsuapi_pfm(schema->prefixmap, mapping_ctr); W_ERROR_NOT_OK_RETURN(status); out = talloc_zero(mem_ctx, struct dsdb_extended_replicated_objects); W_ERROR_HAVE_NO_MEMORY(out); out->version = DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION; out->partition_dn = ldb_dn_new(out, ldb, partition_dn); W_ERROR_HAVE_NO_MEMORY(out->partition_dn); out->source_dsa = source_dsa; out->uptodateness_vector= uptodateness_vector; out->num_objects = object_count; out->objects = talloc_array(out, struct dsdb_extended_replicated_object, out->num_objects); W_ERROR_HAVE_NO_MEMORY(out->objects); /* pass the linked attributes down to the repl_meta_data module */ out->linked_attributes_count = linked_attributes_count; out->linked_attributes = linked_attributes; for (i=0, cur = first_object; cur; cur = cur->next_object, i++) { if (i == out->num_objects) { return WERR_FOOBAR; } status = dsdb_convert_object_ex(ldb, schema, cur, gensec_skey, out->objects, &out->objects[i]); if (!W_ERROR_IS_OK(status)) { DEBUG(0,("Failed to convert object %s\n", cur->object.identifier->dn)); return status; } } if (i != out->num_objects) { return WERR_FOOBAR; } *objects = out; return WERR_OK; }
/* normalise a ldb attribute list */ static PyObject *py_dsdb_normalise_attributes(PyObject *self, PyObject *args) { PyObject *py_ldb, *el_list, *ret; struct ldb_context *ldb; char *ldap_display_name; const struct dsdb_attribute *a; struct dsdb_schema *schema; struct dsdb_syntax_ctx syntax_ctx; struct ldb_message_element *el; struct drsuapi_DsReplicaAttribute *attr; TALLOC_CTX *tmp_ctx; WERROR werr; Py_ssize_t i; if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &ldap_display_name, &el_list)) { return NULL; } PyErr_LDB_OR_RAISE(py_ldb, ldb); if (!PyList_Check(el_list)) { PyErr_Format(PyExc_TypeError, "ldif_elements must be a list"); return NULL; } schema = dsdb_get_schema(ldb, NULL); if (!schema) { PyErr_SetString(PyExc_RuntimeError, "Failed to find a schema from ldb"); return NULL; } a = dsdb_attribute_by_lDAPDisplayName(schema, ldap_display_name); if (a == NULL) { PyErr_Format(PyExc_KeyError, "Failed to find attribute '%s'", ldap_display_name); return NULL; } dsdb_syntax_ctx_init(&syntax_ctx, ldb, schema); syntax_ctx.is_schema_nc = false; tmp_ctx = talloc_new(ldb); if (tmp_ctx == NULL) { PyErr_NoMemory(); return NULL; } el = talloc_zero(tmp_ctx, struct ldb_message_element); if (el == NULL) { PyErr_NoMemory(); talloc_free(tmp_ctx); return NULL; } el->name = ldap_display_name; el->num_values = PyList_Size(el_list); el->values = talloc_array(el, struct ldb_val, el->num_values); if (el->values == NULL) { PyErr_NoMemory(); talloc_free(tmp_ctx); return NULL; } for (i = 0; i < el->num_values; i++) { PyObject *item = PyList_GetItem(el_list, i); if (!PyString_Check(item)) { PyErr_Format(PyExc_TypeError, "ldif_elements should be strings"); talloc_free(tmp_ctx); return NULL; } el->values[i].data = (uint8_t *)PyString_AsString(item); el->values[i].length = PyString_Size(item); } /* Normalise "objectClass" attribute if needed */ if (ldb_attr_cmp(a->lDAPDisplayName, "objectClass") == 0) { int iret; iret = dsdb_sort_objectClass_attr(ldb, schema, el, tmp_ctx, el); if (iret != LDB_SUCCESS) { PyErr_SetString(PyExc_RuntimeError, ldb_errstring(ldb)); talloc_free(tmp_ctx); return NULL; } } /* first run ldb_to_drsuapi, then convert back again. This has * the effect of normalising the attributes */ attr = talloc_zero(tmp_ctx, struct drsuapi_DsReplicaAttribute); if (attr == NULL) { PyErr_NoMemory(); talloc_free(tmp_ctx); return NULL; } werr = a->syntax->ldb_to_drsuapi(&syntax_ctx, a, el, attr, attr); PyErr_WERROR_NOT_OK_RAISE(werr); /* now convert back again */ werr = a->syntax->drsuapi_to_ldb(&syntax_ctx, a, attr, el, el); PyErr_WERROR_NOT_OK_RAISE(werr); ret = py_return_ndr_struct("ldb", "MessageElement", el, el); talloc_free(tmp_ctx); return ret; }
WERROR dsdb_origin_objects_commit(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct drsuapi_DsReplicaObjectListItem *first_object, uint32_t *_num, struct drsuapi_DsReplicaObjectIdentifier2 **_ids) { WERROR status; const struct dsdb_schema *schema; const struct drsuapi_DsReplicaObjectListItem *cur; struct ldb_message **objects; struct drsuapi_DsReplicaObjectIdentifier2 *ids; uint32_t i; uint32_t num_objects = 0; const char * const attrs[] = { "objectGUID", "objectSid", NULL }; struct ldb_result *res; int ret; schema = dsdb_get_schema(ldb); if (!schema) { return WERR_DS_SCHEMA_NOT_LOADED; } for (cur = first_object; cur; cur = cur->next_object) { num_objects++; } if (num_objects == 0) { return WERR_OK; } ret = ldb_transaction_start(ldb); if (ret != LDB_SUCCESS) { return WERR_DS_INTERNAL_FAILURE; } objects = talloc_array(mem_ctx, struct ldb_message *, num_objects); if (objects == NULL) { status = WERR_NOMEM; goto cancel; } for (i=0, cur = first_object; cur; cur = cur->next_object, i++) { status = dsdb_convert_object(ldb, schema, cur, objects, &objects[i]); if (!W_ERROR_IS_OK(status)) { goto cancel; } } ids = talloc_array(mem_ctx, struct drsuapi_DsReplicaObjectIdentifier2, num_objects); if (ids == NULL) { status = WERR_NOMEM; goto cancel; } for (i=0; i < num_objects; i++) { struct dom_sid *sid = NULL; struct ldb_request *add_req; DEBUG(6,(__location__ ": adding %s\n", ldb_dn_get_linearized(objects[i]->dn))); ret = ldb_build_add_req(&add_req, ldb, objects, objects[i], NULL, NULL, ldb_op_default_callback, NULL); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ret = ldb_request(ldb, add_req); if (ret == LDB_SUCCESS) { ret = ldb_wait(add_req->handle, LDB_WAIT_ALL); } if (ret != LDB_SUCCESS) { DEBUG(0,(__location__ ": Failed add of %s - %s\n", ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb))); status = WERR_DS_INTERNAL_FAILURE; goto cancel; } talloc_free(add_req); ret = ldb_search(ldb, objects, &res, objects[i]->dn, LDB_SCOPE_BASE, attrs, "(objectClass=*)"); if (ret != LDB_SUCCESS) { status = WERR_DS_INTERNAL_FAILURE; goto cancel; } ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID"); sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid"); if (sid) { ids[i].sid = *sid; } else { ZERO_STRUCT(ids[i].sid); } } ret = ldb_transaction_commit(ldb); if (ret != LDB_SUCCESS) { return WERR_DS_INTERNAL_FAILURE; } talloc_free(objects); *_num = num_objects; *_ids = ids; return WERR_OK; cancel: talloc_free(objects); ldb_transaction_cancel(ldb); return status; }
static int acl_modify(struct ldb_module *module, struct ldb_request *req) { int ret; struct ldb_context *ldb = ldb_module_get_ctx(module); const struct dsdb_schema *schema = dsdb_get_schema(ldb); int i; bool modify_sd = false; const struct GUID *guid; uint32_t access_granted; struct object_tree *root = NULL; struct object_tree *new_node = NULL; NTSTATUS status; struct ldb_result *acl_res; struct security_descriptor *sd; struct dom_sid *sid = NULL; TALLOC_CTX *tmp_ctx = talloc_new(req); static const char *acl_attrs[] = { "nTSecurityDescriptor", "objectClass", "objectSid", NULL }; /* Don't print this debug statement if elements[0].name is going to be NULL */ if(req->op.mod.message->num_elements > 0) { DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name)); } if (what_is_user(module) == SECURITY_SYSTEM) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.mod.message->dn)) { return ldb_next_request(module, req); } ret = ldb_search(ldb, req, &acl_res, req->op.mod.message->dn, LDB_SCOPE_BASE, acl_attrs, NULL); if (ret != LDB_SUCCESS) { return ret; } ret = get_sd_from_ldb_message(req, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { DEBUG(10, ("acl_modify: cannot get descriptor\n")); return ret; } /* Theoretically we pass the check if the object has no sd */ if (!sd) { return LDB_SUCCESS; } guid = get_oc_guid_from_message(module,acl_res->msgs[0]); if (!guid) { DEBUG(10, ("acl_modify: cannot get guid\n")); goto fail; } ret = get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP, &root, &new_node)) { DEBUG(10, ("acl_modify: cannot add to object tree\n")); goto fail; } for (i=0; i < req->op.mod.message->num_elements; i++){ const struct dsdb_attribute *attr; /* clearTextPassword is not in schema */ if (strcmp("clearTextPassword", req->op.mod.message->elements[i].name) == 0) { attr = dsdb_attribute_by_lDAPDisplayName(schema, "unicodePwd"); } else { attr = dsdb_attribute_by_lDAPDisplayName(schema, req->op.mod.message->elements[i].name); } if (strcmp("nTSecurityDescriptor", req->op.mod.message->elements[i].name) == 0) { modify_sd = true; } else { if (!attr) { DEBUG(10, ("acl_modify: cannot find attribute %s\n", req->op.mod.message->elements[i].name)); goto fail; } if (!insert_in_object_tree(tmp_ctx, &attr->attributeSecurityGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) { DEBUG(10, ("acl_modify: cannot add to object tree securityGUID\n")); goto fail; } if (!insert_in_object_tree(tmp_ctx, &attr->schemaIDGUID, SEC_ADS_WRITE_PROP, &new_node, &new_node)) { DEBUG(10, ("acl_modify: cannot add to object tree attributeGUID\n")); goto fail; } } } if (root->num_of_children > 0) { status = sec_access_check_ds(sd, acl_user_token(module), SEC_ADS_WRITE_PROP, &access_granted, root, sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Object %s nas no write property access\n", ldb_dn_get_linearized(req->op.mod.message->dn))); acl_debug(sd, acl_user_token(module), req->op.mod.message->dn, true, 10); talloc_free(tmp_ctx); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } } if (modify_sd) { status = sec_access_check_ds(sd, acl_user_token(module), SEC_STD_WRITE_DAC, &access_granted, NULL, sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Object %s nas no write dacl access\n", ldb_dn_get_linearized(req->op.mod.message->dn))); acl_debug(sd, acl_user_token(module), req->op.mod.message->dn, true, 10); talloc_free(tmp_ctx); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } } talloc_free(tmp_ctx); return ldb_next_request(module, req); fail: talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; }
static int acl_rename(struct ldb_module *module, struct ldb_request *req) { int ret; struct ldb_dn *oldparent = ldb_dn_get_parent(req, req->op.rename.olddn); struct ldb_dn *newparent = ldb_dn_get_parent(req, req->op.rename.newdn); struct ldb_context *ldb; struct security_descriptor *sd = NULL; struct dom_sid *sid = NULL; struct ldb_result *acl_res; const struct GUID *guid; struct object_tree *root = NULL; struct object_tree *new_node = NULL; TALLOC_CTX *tmp_ctx = talloc_new(req); NTSTATUS status; uint32_t access_granted; static const char *acl_attrs[] = { "nTSecurityDescriptor", "objectClass", "objectSid", NULL }; DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn))); if (what_is_user(module) == SECURITY_SYSTEM) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.rename.olddn)) { return ldb_next_request(module, req); } ldb = ldb_module_get_ctx(module); /* TODO search to include deleted objects */ ret = ldb_search(ldb, req, &acl_res, req->op.rename.olddn, LDB_SCOPE_BASE, acl_attrs, NULL); /* we sould be able to find the parent */ if (ret != LDB_SUCCESS) { DEBUG(10,("acl: failed to find object %s\n", ldb_dn_get_linearized(req->op.rename.olddn))); return ret; } guid = get_oc_guid_from_message(module,acl_res->msgs[0]); if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP, &root, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; }; guid = attribute_schemaid_guid_by_lDAPDisplayName(dsdb_get_schema(ldb), "name"); if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP, &new_node, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; }; ret = get_sd_from_ldb_message(req, acl_res->msgs[0], &sd); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } /* Theoretically we pass the check if the object has no sd */ if (!sd) { return LDB_SUCCESS; } ret = get_dom_sid_from_ldb_message(req, acl_res->msgs[0], &sid); if (ret != LDB_SUCCESS) { return LDB_ERR_OPERATIONS_ERROR; } status = sec_access_check_ds(sd, acl_user_token(module), SEC_ADS_WRITE_PROP, &access_granted, root, sid); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Object %s nas no wp on name\n", ldb_dn_get_linearized(req->op.rename.olddn))); acl_debug(sd, acl_user_token(module), req->op.rename.olddn, true, 10); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } if (ldb_dn_compare(oldparent, newparent) == 0) { /* regular rename, not move, nothing more to do */ return ldb_next_request(module, req); } /* What exactly to do in this case? It would fail anyway.. */ if ((ldb_dn_compare(req->op.rename.newdn, (ldb_get_schema_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.rename.newdn, (ldb_get_config_basedn(ldb))) == 0) || (ldb_dn_compare(req->op.rename.newdn, (ldb_get_root_basedn(ldb))) == 0)) { DEBUG(10,("acl:moving as an NC\n")); return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } /* new parent should have create child */ talloc_free(tmp_ctx); tmp_ctx = talloc_new(req); root = NULL; new_node = NULL; guid = get_oc_guid_from_message(module,acl_res->msgs[0]); if (!guid) { DEBUG(10,("acl:renamed object has no object class\n")); return ldb_module_done(req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); } if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_CREATE_CHILD, &root, &new_node)) { return LDB_ERR_OPERATIONS_ERROR; } ret = check_access_on_dn(module, req, newparent, SEC_ADS_CREATE_CHILD, root); if (ret != LDB_SUCCESS) { DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn))); return ret; } /* do we have delete object on the object? */ status = sec_access_check_ds(sd, acl_user_token(module), SEC_STD_DELETE, &access_granted, NULL, sid); if (NT_STATUS_IS_OK(status)) { return ldb_next_request(module, req); } /* what about delete child on the current parent */ ret = check_access_on_dn(module, req, oldparent, SEC_ADS_DELETE_CHILD, NULL); if (ret != LDB_SUCCESS) { DEBUG(10,("acl:access_denied renaming %s", ldb_dn_get_linearized(req->op.rename.olddn))); return ldb_module_done(req, NULL, NULL, ret); } return ldb_next_request(module, req); }
/* convert a python string to a DRSUAPI drsuapi_DsReplicaAttribute attribute */ static PyObject *py_dsdb_DsReplicaAttribute(PyObject *self, PyObject *args) { PyObject *py_ldb, *el_list, *ret; struct ldb_context *ldb; char *ldap_display_name; const struct dsdb_attribute *a; struct dsdb_schema *schema; struct dsdb_syntax_ctx syntax_ctx; struct ldb_message_element *el; struct drsuapi_DsReplicaAttribute *attr; TALLOC_CTX *tmp_ctx; WERROR werr; Py_ssize_t i; if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &ldap_display_name, &el_list)) { return NULL; } PyErr_LDB_OR_RAISE(py_ldb, ldb); if (!PyList_Check(el_list)) { PyErr_Format(PyExc_TypeError, "ldif_elements must be a list"); return NULL; } schema = dsdb_get_schema(ldb, NULL); if (!schema) { PyErr_SetString(PyExc_RuntimeError, "Failed to find a schema from ldb"); return NULL; } a = dsdb_attribute_by_lDAPDisplayName(schema, ldap_display_name); if (a == NULL) { PyErr_Format(PyExc_KeyError, "Failed to find attribute '%s'", ldap_display_name); return NULL; } dsdb_syntax_ctx_init(&syntax_ctx, ldb, schema); syntax_ctx.is_schema_nc = false; tmp_ctx = talloc_new(ldb); if (tmp_ctx == NULL) { PyErr_NoMemory(); return NULL; } el = talloc_zero(tmp_ctx, struct ldb_message_element); if (el == NULL) { PyErr_NoMemory(); talloc_free(tmp_ctx); return NULL; } el->name = ldap_display_name; el->num_values = PyList_Size(el_list); el->values = talloc_array(el, struct ldb_val, el->num_values); if (el->values == NULL) { PyErr_NoMemory(); talloc_free(tmp_ctx); return NULL; } for (i = 0; i < el->num_values; i++) { PyObject *item = PyList_GetItem(el_list, i); if (!PyString_Check(item)) { PyErr_Format(PyExc_TypeError, "ldif_elements should be strings"); talloc_free(tmp_ctx); return NULL; } el->values[i].data = (uint8_t *)PyString_AsString(item); el->values[i].length = PyString_Size(item); } attr = talloc_zero(tmp_ctx, struct drsuapi_DsReplicaAttribute); if (attr == NULL) { PyErr_NoMemory(); talloc_free(tmp_ctx); return NULL; } werr = a->syntax->ldb_to_drsuapi(&syntax_ctx, a, el, attr, attr); PyErr_WERROR_NOT_OK_RAISE(werr); ret = py_return_ndr_struct("samba.dcerpc.drsuapi", "DsReplicaAttribute", attr, attr); talloc_free(tmp_ctx); return ret; }