/* compare two dns */ static int samba_ldb_dn_link_comparison(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *v1, const struct ldb_val *v2) { struct ldb_dn *dn1 = NULL, *dn2 = NULL; int ret; if (dsdb_dn_is_deleted_val(v1)) { /* If the DN is deleted, then we can't search for it */ return -1; } if (dsdb_dn_is_deleted_val(v2)) { /* If the DN is deleted, then we can't search for it */ return -1; } dn1 = ldb_dn_from_ldb_val(mem_ctx, ldb, v1); if ( ! ldb_dn_validate(dn1)) return -1; dn2 = ldb_dn_from_ldb_val(mem_ctx, ldb, v2); if ( ! ldb_dn_validate(dn2)) { talloc_free(dn1); return -1; } ret = ldb_dn_compare(dn1, dn2); talloc_free(dn1); talloc_free(dn2); return ret; }
/* Copy a DN with the base DN of the remote partition. */ static struct ldb_dn *ldb_dn_rebase_remote(void *mem_ctx, const struct ldb_map_context *data, struct ldb_dn *dn) { struct ldb_dn *new_dn; new_dn = ldb_dn_copy(mem_ctx, dn); if ( ! ldb_dn_validate(new_dn)) { talloc_free(new_dn); return NULL; } /* may be we don't need to rebase at all */ if ( ! data->remote_base_dn || ! data->local_base_dn) { return new_dn; } if ( ! ldb_dn_remove_base_components(new_dn, ldb_dn_get_comp_num(data->local_base_dn))) { talloc_free(new_dn); return NULL; } if ( ! ldb_dn_add_base(new_dn, data->remote_base_dn)) { talloc_free(new_dn); return NULL; } return new_dn; }
/* Map a DN contained in an ldb value into the local partition. */ static struct ldb_val ldb_dn_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val) { struct ldb_context *ldb; struct ldb_dn *dn, *newdn; struct ldb_val newval; ldb = ldb_module_get_ctx(module); dn = ldb_dn_from_ldb_val(mem_ctx, ldb, val); if (! ldb_dn_validate(dn)) { newval.length = 0; newval.data = NULL; talloc_free(dn); return newval; } newdn = ldb_dn_map_remote(module, mem_ctx, dn); talloc_free(dn); newval.length = 0; newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn); if (newval.data) { newval.length = strlen((char *)newval.data); } talloc_free(newdn); return newval; }
WERROR dreplsrv_load_partitions(struct dreplsrv_service *s) { WERROR status; static const char *attrs[] = { "namingContexts", NULL }; unsigned int i; int ret; TALLOC_CTX *tmp_ctx; struct ldb_result *res; struct ldb_message_element *el; tmp_ctx = talloc_new(s); W_ERROR_HAVE_NO_MEMORY(tmp_ctx); ret = ldb_search(s->samdb, tmp_ctx, &res, ldb_dn_new(tmp_ctx, s->samdb, ""), LDB_SCOPE_BASE, attrs, NULL); if (ret != LDB_SUCCESS) { DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(s->samdb))); talloc_free(tmp_ctx); return WERR_DS_DRA_INTERNAL_ERROR; } el = ldb_msg_find_element(res->msgs[0], "namingContexts"); if (!el) { DEBUG(1,("Finding namingContexts element in root_res failed: %s\n", ldb_errstring(s->samdb))); talloc_free(tmp_ctx); return WERR_DS_DRA_INTERNAL_ERROR; } for (i=0; i<el->num_values; i++) { struct ldb_dn *pdn; struct dreplsrv_partition *p; pdn = ldb_dn_from_ldb_val(tmp_ctx, s->samdb, &el->values[i]); if (pdn == NULL) { talloc_free(tmp_ctx); return WERR_DS_DRA_INTERNAL_ERROR; } if (!ldb_dn_validate(pdn)) { return WERR_DS_DRA_INTERNAL_ERROR; } p = talloc_zero(s, struct dreplsrv_partition); W_ERROR_HAVE_NO_MEMORY(p); p->dn = talloc_steal(p, pdn); DLIST_ADD(s->partitions, p); DEBUG(2, ("dreplsrv_partition[%s] loaded\n", ldb_dn_get_linearized(p->dn))); } talloc_free(tmp_ctx); status = dreplsrv_refresh_partitions(s); W_ERROR_NOT_OK_RETURN(status); return WERR_OK; }
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; }
WERROR dreplsrv_load_partitions(struct dreplsrv_service *s) { WERROR status; struct ldb_dn *basedn; struct ldb_result *r; struct ldb_message_element *el; static const char *attrs[] = { "namingContexts", NULL }; uint32_t i; int ret; basedn = ldb_dn_new(s, s->samdb, NULL); W_ERROR_HAVE_NO_MEMORY(basedn); ret = ldb_search(s->samdb, s, &r, basedn, LDB_SCOPE_BASE, attrs, "(objectClass=*)"); talloc_free(basedn); if (ret != LDB_SUCCESS) { return WERR_FOOBAR; } else if (r->count != 1) { talloc_free(r); return WERR_FOOBAR; } el = ldb_msg_find_element(r->msgs[0], "namingContexts"); if (!el) { return WERR_FOOBAR; } for (i=0; el && i < el->num_values; i++) { const char *v = (const char *)el->values[i].data; struct ldb_dn *pdn; struct dreplsrv_partition *p; pdn = ldb_dn_new(s, s->samdb, v); if (!ldb_dn_validate(pdn)) { return WERR_FOOBAR; } p = talloc_zero(s, struct dreplsrv_partition); W_ERROR_HAVE_NO_MEMORY(p); p->dn = talloc_steal(p, pdn); DLIST_ADD(s->partitions, p); DEBUG(2, ("dreplsrv_partition[%s] loaded\n", v)); } talloc_free(r); status = dreplsrv_refresh_partitions(s); W_ERROR_NOT_OK_RETURN(status); return WERR_OK; }
/* drsuapi_DsRemoveDSServer */ static WERROR dcesrv_drsuapi_DsRemoveDSServer(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct drsuapi_DsRemoveDSServer *r) { struct drsuapi_bind_state *b_state; struct dcesrv_handle *h; struct ldb_dn *ntds_dn; int ret; bool ok; WERROR status; ZERO_STRUCT(r->out.res); *r->out.level_out = 1; status = drs_security_level_check(dce_call, "DsRemoveDSServer"); if (!W_ERROR_IS_OK(status)) { return status; } DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); b_state = h->data; switch (r->in.level) { case 1: ntds_dn = ldb_dn_new(mem_ctx, b_state->sam_ctx, r->in.req->req1.server_dn); W_ERROR_HAVE_NO_MEMORY(ntds_dn); ok = ldb_dn_validate(ntds_dn); if (!ok) { return WERR_FOOBAR; } /* TODO: it's likely that we need more checks here */ ok = ldb_dn_add_child_fmt(ntds_dn, "CN=NTDS Settings"); if (!ok) { return WERR_FOOBAR; } if (r->in.req->req1.commit) { ret = ldb_delete(b_state->sam_ctx, ntds_dn); if (ret != LDB_SUCCESS) { return WERR_FOOBAR; } } return WERR_OK; default: break; } return WERR_FOOBAR; }
/* make sure we only add repsFrom entries for DCs who are masters for the partition */ static bool check_MasterNC(struct kccsrv_partition *p, struct repsFromToBlob *r, struct ldb_result *res) { struct repsFromTo1 *r1 = &r->ctr.ctr1; struct GUID invocation_id = r1->source_dsa_invocation_id; unsigned int i, j; /* we are expecting only version 1 */ SMB_ASSERT(r->version == 1); for (i=0; i<res->count; i++) { struct ldb_message *msg = res->msgs[i]; struct ldb_message_element *el; struct ldb_dn *dn; struct GUID id2 = samdb_result_guid(msg, "invocationID"); if (GUID_all_zero(&id2) || !GUID_equal(&invocation_id, &id2)) { continue; } el = ldb_msg_find_element(msg, "msDS-hasMasterNCs"); if (!el || el->num_values == 0) { el = ldb_msg_find_element(msg, "hasMasterNCs"); if (!el || el->num_values == 0) { continue; } } for (j=0; j<el->num_values; j++) { dn = ldb_dn_from_ldb_val(p, p->service->samdb, &el->values[j]); if (!ldb_dn_validate(dn)) { talloc_free(dn); continue; } if (ldb_dn_compare(dn, p->dn) == 0) { talloc_free(dn); DEBUG(5,("%s %s match on %s in %s\n", r1->other_info->dns_name, el->name, ldb_dn_get_linearized(dn), ldb_dn_get_linearized(msg->dn))); return true; } talloc_free(dn); } } return false; }
struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr_name) { struct ldb_dn *res_dn; const struct ldb_val *v; v = ldb_msg_find_ldb_val(msg, attr_name); if (!v || !v->data) { return NULL; } res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v); if ( ! ldb_dn_validate(res_dn)) { talloc_free(res_dn); return NULL; } return res_dn; }
int main(int argc, const char **argv) { struct ldb_context *ldb; int ret = 0, i; struct ldb_cmdline *options; ldb = ldb_init(NULL, NULL); options = ldb_cmdline_process(ldb, argc, argv, usage); if (options->argc < 1) { usage(); exit(1); } for (i=0;i<options->argc;i++) { struct ldb_dn *dn; dn = ldb_dn_new(ldb, ldb, options->argv[i]); if ( ! ldb_dn_validate(dn)) { printf("Invalid DN format\n"); exit(1); } if (options->recursive) { ret = ldb_delete_recursive(ldb, dn); } else { ret = ldb_delete(ldb, dn); if (ret == 0) { printf("Deleted 1 record\n"); } } if (ret != 0) { printf("delete of '%s' failed - %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb)); } } talloc_free(ldb); return ret; }
/* get pending ops info for a specified DN */ static WERROR kccdrs_replica_get_info_pending_ops(TALLOC_CTX *mem_ctx, struct ldb_context *samdb, struct drsuapi_DsReplicaGetInfo *r, union drsuapi_DsReplicaInfo *reply, struct ldb_dn *dn) { struct timeval now = timeval_current(); if (!ldb_dn_validate(dn)) { return WERR_INVALID_PARAMETER; } reply->pendingops = talloc(mem_ctx, struct drsuapi_DsReplicaOpCtr); W_ERROR_HAVE_NO_MEMORY(reply->pendingops); /* claim no pending ops for now */ reply->pendingops->time = timeval_to_nttime(&now); reply->pendingops->count = 0; reply->pendingops->array = NULL; return WERR_OK; }
/* get cursors2 info for a specified DN */ static WERROR kccdrs_replica_get_info_cursors2(TALLOC_CTX *mem_ctx, struct ldb_context *samdb, struct drsuapi_DsReplicaGetInfo *r, union drsuapi_DsReplicaInfo *reply, struct ldb_dn *dn) { int ret; if (!ldb_dn_validate(dn)) { return WERR_INVALID_PARAMETER; } reply->cursors2 = talloc(mem_ctx, struct drsuapi_DsReplicaCursor2Ctr); W_ERROR_HAVE_NO_MEMORY(reply->cursors2); ret = dsdb_load_udv_v2(samdb, dn, reply->cursors2, &reply->cursors2->array, &reply->cursors2->count); if (ret != LDB_SUCCESS) { return WERR_DS_DRA_BAD_NC; } reply->cursors2->enumeration_context = reply->cursors2->count; return WERR_OK; }
static int samba_ldb_dn_link_canonicalise(struct ldb_context *ldb, void *mem_ctx, const struct ldb_val *in, struct ldb_val *out) { struct ldb_dn *dn; int ret = -1; out->length = 0; out->data = NULL; dn = ldb_dn_from_ldb_val(mem_ctx, ldb, in); if ( ! ldb_dn_validate(dn)) { return LDB_ERR_INVALID_DN_SYNTAX; } /* By including the RMD_FLAGS of a deleted DN, we ensure it * does not casually match a not deleted DN */ if (dsdb_dn_is_deleted_val(in)) { out->data = (uint8_t *)talloc_asprintf(mem_ctx, "<RMD_FLAGS=%u>%s", dsdb_dn_val_rmd_flags(in), ldb_dn_get_casefold(dn)); } else { out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn); } if (out->data == NULL) { goto done; } out->length = strlen((char *)out->data); ret = 0; done: talloc_free(dn); return ret; }
/* Map a DN contained in an ldb value into the local partition. */ static struct ldb_val ldb_dn_convert_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_val *val) { struct ldb_dn *dn, *newdn; struct ldb_val newval; dn = ldb_dn_new(mem_ctx, module->ldb, (char *)val->data); if (! ldb_dn_validate(dn)) { newval.length = 0; newval.data = NULL; talloc_free(dn); return newval; } newdn = ldb_dn_map_remote(module, mem_ctx, dn); talloc_free(dn); newval.length = 0; newval.data = (uint8_t *)ldb_dn_alloc_linearized(mem_ctx, newdn); if (newval.data) { newval.length = strlen((char *)newval.data); } talloc_free(newdn); return newval; }
static bool torture_ldb_dn_extended(struct torture_context *torture) { TALLOC_CTX *mem_ctx = talloc_new(torture); struct ldb_context *ldb; struct ldb_dn *dn, *dn2; DATA_BLOB sid_blob = strhex_to_data_blob(mem_ctx, hex_sid); DATA_BLOB guid_blob = strhex_to_data_blob(mem_ctx, hex_guid); const char *dn_str = "cn=admin,cn=users,dc=samba,dc=org"; torture_assert(torture, ldb = ldb_init(mem_ctx, torture->ev), "Failed to init ldb"); torture_assert_int_equal(torture, ldb_register_samba_handlers(ldb), 0, "Failed to register Samba handlers"); ldb_set_utf8_fns(ldb, NULL, wrap_casefold); /* Check behaviour of a normal DN */ torture_assert(torture, dn = ldb_dn_new(mem_ctx, ldb, dn_str), "Failed to create a 'normal' DN"); torture_assert(torture, ldb_dn_validate(dn), "Failed to validate 'normal' DN"); torture_assert(torture, ldb_dn_has_extended(dn) == false, "Should not find plain DN to be 'extended'"); torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") == NULL, "Should not find an SID on plain DN"); torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") == NULL, "Should not find an GUID on plain DN"); torture_assert(torture, ldb_dn_get_extended_component(dn, "WKGUID") == NULL, "Should not find an WKGUID on plain DN"); /* Now make an extended DN */ torture_assert(torture, dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>;<SID=%s>;%s", guid, sid, dn_str), "Failed to create an 'extended' DN"); torture_assert(torture, dn2 = ldb_dn_copy(mem_ctx, dn), "Failed to copy the 'extended' DN"); talloc_free(dn); dn = dn2; torture_assert(torture, ldb_dn_validate(dn), "Failed to validate 'extended' DN"); torture_assert(torture, ldb_dn_has_extended(dn) == true, "Should find extended DN to be 'extended'"); torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") != NULL, "Should find an SID on extended DN"); torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") != NULL, "Should find an GUID on extended DN"); torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "SID"), sid_blob, "Extended DN SID incorect"); torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "GUID"), guid_blob, "Extended DN GUID incorect"); torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), dn_str, "linearized DN incorrect"); torture_assert_str_equal(torture, ldb_dn_get_casefold(dn), strupper_talloc(mem_ctx, dn_str), "casefolded DN incorrect"); torture_assert_str_equal(torture, ldb_dn_get_component_name(dn, 0), "cn", "componet zero incorrect"); torture_assert_data_blob_equal(torture, *ldb_dn_get_component_val(dn, 0), data_blob_string_const("admin"), "componet zero incorrect"); torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 1), talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s", guid, sid, dn_str), "Clear extended linearized DN incorrect"); torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 0), talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s", hex_guid, hex_sid, dn_str), "HEX extended linearized DN incorrect"); torture_assert(torture, ldb_dn_remove_child_components(dn, 1) == true, "Failed to remove DN child"); torture_assert(torture, ldb_dn_has_extended(dn) == false, "Extended DN flag should be cleared after child element removal"); torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") == NULL, "Should not find an SID on DN"); torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") == NULL, "Should not find an GUID on DN"); /* TODO: test setting these in the other order, and ensure it still comes out 'GUID first' */ torture_assert_int_equal(torture, ldb_dn_set_extended_component(dn, "GUID", &guid_blob), 0, "Failed to set a GUID on DN"); torture_assert_int_equal(torture, ldb_dn_set_extended_component(dn, "SID", &sid_blob), 0, "Failed to set a SID on DN"); torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "SID"), sid_blob, "Extended DN SID incorect"); torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "GUID"), guid_blob, "Extended DN GUID incorect"); torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "cn=users,dc=samba,dc=org", "linearized DN incorrect"); torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 1), talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s", guid, sid, "cn=users,dc=samba,dc=org"), "Clear extended linearized DN incorrect"); torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 0), talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s", hex_guid, hex_sid, "cn=users,dc=samba,dc=org"), "HEX extended linearized DN incorrect"); /* Now check a 'just GUID' DN (clear format) */ torture_assert(torture, dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>", guid), "Failed to create an 'extended' DN"); torture_assert(torture, ldb_dn_validate(dn), "Failed to validate 'extended' DN"); torture_assert(torture, ldb_dn_has_extended(dn) == true, "Should find extended DN to be 'extended'"); torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") == NULL, "Should not find an SID on this DN"); torture_assert_int_equal(torture, ldb_dn_get_comp_num(dn), 0, "Should not find an 'normal' componet on this DN"); torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") != NULL, "Should find an GUID on this DN"); torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "GUID"), guid_blob, "Extended DN GUID incorect"); torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "", "linearized DN incorrect"); torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 1), talloc_asprintf(mem_ctx, "<GUID=%s>", guid), "Clear extended linearized DN incorrect"); torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 0), talloc_asprintf(mem_ctx, "<GUID=%s>", hex_guid), "HEX extended linearized DN incorrect"); /* Now check a 'just GUID' DN (HEX format) */ torture_assert(torture, dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>", hex_guid), "Failed to create an 'extended' DN"); torture_assert(torture, ldb_dn_validate(dn), "Failed to validate 'extended' DN"); torture_assert(torture, ldb_dn_has_extended(dn) == true, "Should find extended DN to be 'extended'"); torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") == NULL, "Should not find an SID on this DN"); torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") != NULL, "Should find an GUID on this DN"); torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "GUID"), guid_blob, "Extended DN GUID incorect"); torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "", "linearized DN incorrect"); /* Now check a 'just SID' DN (clear format) */ torture_assert(torture, dn = ldb_dn_new_fmt(mem_ctx, ldb, "<SID=%s>", sid), "Failed to create an 'extended' DN"); torture_assert(torture, ldb_dn_validate(dn), "Failed to validate 'extended' DN"); torture_assert(torture, ldb_dn_has_extended(dn) == true, "Should find extended DN to be 'extended'"); torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") == NULL, "Should not find an SID on this DN"); torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") != NULL, "Should find an SID on this DN"); torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "SID"), sid_blob, "Extended DN SID incorect"); torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "", "linearized DN incorrect"); torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 1), talloc_asprintf(mem_ctx, "<SID=%s>", sid), "Clear extended linearized DN incorrect"); torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 0), talloc_asprintf(mem_ctx, "<SID=%s>", hex_sid), "HEX extended linearized DN incorrect"); /* Now check a 'just SID' DN (HEX format) */ torture_assert(torture, dn = ldb_dn_new_fmt(mem_ctx, ldb, "<SID=%s>", hex_sid), "Failed to create an 'extended' DN"); torture_assert(torture, ldb_dn_validate(dn), "Failed to validate 'extended' DN"); torture_assert(torture, ldb_dn_has_extended(dn) == true, "Should find extended DN to be 'extended'"); torture_assert(torture, ldb_dn_get_extended_component(dn, "GUID") == NULL, "Should not find an SID on this DN"); torture_assert(torture, ldb_dn_get_extended_component(dn, "SID") != NULL, "Should find an SID on this DN"); torture_assert_data_blob_equal(torture, *ldb_dn_get_extended_component(dn, "SID"), sid_blob, "Extended DN SID incorect"); torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "", "linearized DN incorrect"); talloc_free(mem_ctx); return true; }
/* * complete a domain join, when joining to a AD domain: * 1.) connect and bind to the DRSUAPI pipe * 2.) do a DsCrackNames() to find the machine account dn * 3.) connect to LDAP * 4.) do an ldap search to find the "msDS-KeyVersionNumber" of the machine account * 5.) set the servicePrincipalName's of the machine account via LDAP, (maybe we should use DsWriteAccountSpn()...) * 6.) do a DsCrackNames() to find the domain dn * 7.) find out Site specific stuff, look at libnet_JoinSite() for details */ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_JoinDomain *r) { NTSTATUS status; TALLOC_CTX *tmp_ctx; const char *realm = r->out.realm; struct dcerpc_binding *samr_binding = r->out.samr_binding; struct dcerpc_pipe *drsuapi_pipe; struct dcerpc_binding *drsuapi_binding; struct drsuapi_DsBind r_drsuapi_bind; struct drsuapi_DsCrackNames r_crack_names; struct drsuapi_DsNameString names[1]; struct policy_handle drsuapi_bind_handle; struct GUID drsuapi_bind_guid; struct ldb_context *remote_ldb; struct ldb_dn *account_dn; const char *account_dn_str; const char *remote_ldb_url; struct ldb_result *res; struct ldb_message *msg; int ret, rtn; const char * const attrs[] = { "msDS-KeyVersionNumber", "servicePrincipalName", "dNSHostName", "objectGUID", NULL, }; r->out.error_string = NULL; /* We need to convert between a samAccountName and domain to a * DN in the directory. The correct way to do this is with * DRSUAPI CrackNames */ /* Fiddle with the bindings, so get to DRSUAPI on * NCACN_IP_TCP, sealed */ tmp_ctx = talloc_named(r, 0, "libnet_JoinADSDomain temp context"); if (!tmp_ctx) { r->out.error_string = NULL; return NT_STATUS_NO_MEMORY; } drsuapi_binding = talloc(tmp_ctx, struct dcerpc_binding); if (!drsuapi_binding) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } *drsuapi_binding = *samr_binding; /* DRSUAPI is only available on IP_TCP, and locally on NCALRPC */ if (drsuapi_binding->transport != NCALRPC) { drsuapi_binding->transport = NCACN_IP_TCP; } drsuapi_binding->endpoint = NULL; drsuapi_binding->flags |= DCERPC_SEAL; status = dcerpc_pipe_connect_b(tmp_ctx, &drsuapi_pipe, drsuapi_binding, &ndr_table_drsuapi, ctx->cred, ctx->event_ctx, ctx->lp_ctx); if (!NT_STATUS_IS_OK(status)) { r->out.error_string = talloc_asprintf(r, "Connection to DRSUAPI pipe of PDC of domain '%s' failed: %s", r->out.domain_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } /* get a DRSUAPI pipe handle */ GUID_from_string(DRSUAPI_DS_BIND_GUID, &drsuapi_bind_guid); r_drsuapi_bind.in.bind_guid = &drsuapi_bind_guid; r_drsuapi_bind.in.bind_info = NULL; r_drsuapi_bind.out.bind_handle = &drsuapi_bind_handle; status = dcerpc_drsuapi_DsBind(drsuapi_pipe, tmp_ctx, &r_drsuapi_bind); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsBind failed - %s", dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code)); talloc_free(tmp_ctx); return status; } else { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsBind failed - %s", nt_errstr(status)); talloc_free(tmp_ctx); return status; } } else if (!W_ERROR_IS_OK(r_drsuapi_bind.out.result)) { r->out.error_string = talloc_asprintf(r, "DsBind failed - %s", win_errstr(r_drsuapi_bind.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Actually 'crack' the names */ ZERO_STRUCT(r_crack_names); r_crack_names.in.bind_handle = &drsuapi_bind_handle; r_crack_names.in.level = 1; r_crack_names.in.req = talloc(r, union drsuapi_DsNameRequest); if (!r_crack_names.in.req) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } r_crack_names.in.req->req1.codepage = 1252; /* western european */ r_crack_names.in.req->req1.language = 0x00000407; /* german */ r_crack_names.in.req->req1.count = 1; r_crack_names.in.req->req1.names = names; r_crack_names.in.req->req1.format_flags = DRSUAPI_DS_NAME_FLAG_NO_FLAGS; r_crack_names.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY; r_crack_names.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; names[0].str = dom_sid_string(tmp_ctx, r->out.account_sid); if (!names[0].str) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } r_crack_names.out.ctr = talloc(r, union drsuapi_DsNameCtr); r_crack_names.out.level_out = talloc(r, int32_t); if (!r_crack_names.out.ctr || !r_crack_names.out.level_out) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } status = dcerpc_drsuapi_DsCrackNames(drsuapi_pipe, tmp_ctx, &r_crack_names); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", names[0].str, dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code)); talloc_free(tmp_ctx); return status; } else { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", names[0].str, nt_errstr(status)); talloc_free(tmp_ctx); return status; } } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (*r_crack_names.out.level_out != 1 || !r_crack_names.out.ctr->ctr1 || r_crack_names.out.ctr->ctr1->count != 1) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed"); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } else if (r_crack_names.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: %d", r_crack_names.out.ctr->ctr1->array[0].status); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (r_crack_names.out.ctr->ctr1->array[0].result_name == NULL) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: no result name"); talloc_free(tmp_ctx); return NT_STATUS_INVALID_PARAMETER; } /* Store the DN of our machine account. */ account_dn_str = r_crack_names.out.ctr->ctr1->array[0].result_name; /* Now we know the user's DN, open with LDAP, read and modify a few things */ remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s", drsuapi_binding->target_hostname); if (!remote_ldb_url) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } remote_ldb = ldb_wrap_connect(tmp_ctx, ctx->event_ctx, ctx->lp_ctx, remote_ldb_url, NULL, ctx->cred, 0, NULL); if (!remote_ldb) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } account_dn = ldb_dn_new(tmp_ctx, remote_ldb, account_dn_str); if (! ldb_dn_validate(account_dn)) { r->out.error_string = talloc_asprintf(r, "Invalid account dn: %s", account_dn_str); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* search for the user's record */ ret = ldb_search(remote_ldb, tmp_ctx, &res, account_dn, LDB_SCOPE_BASE, attrs, NULL); if (ret != LDB_SUCCESS) { r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - %s", account_dn_str, ldb_errstring(remote_ldb)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } if (res->count != 1) { r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - found %d entries", account_dn_str, res->count); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Prepare a new message, for the modify */ msg = ldb_msg_new(tmp_ctx); if (!msg) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } msg->dn = res->msgs[0]->dn; { int i; const char *service_principal_name[6]; const char *dns_host_name = strlower_talloc(tmp_ctx, talloc_asprintf(tmp_ctx, "%s.%s", r->in.netbios_name, realm)); if (!dns_host_name) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } service_principal_name[0] = talloc_asprintf(tmp_ctx, "host/%s", dns_host_name); service_principal_name[1] = talloc_asprintf(tmp_ctx, "host/%s", strlower_talloc(tmp_ctx, r->in.netbios_name)); service_principal_name[2] = talloc_asprintf(tmp_ctx, "host/%s/%s", dns_host_name, realm); service_principal_name[3] = talloc_asprintf(tmp_ctx, "host/%s/%s", strlower_talloc(tmp_ctx, r->in.netbios_name), realm); service_principal_name[4] = talloc_asprintf(tmp_ctx, "host/%s/%s", dns_host_name, r->out.domain_name); service_principal_name[5] = talloc_asprintf(tmp_ctx, "host/%s/%s", strlower_talloc(tmp_ctx, r->in.netbios_name), r->out.domain_name); for (i=0; i < ARRAY_SIZE(service_principal_name); i++) { if (!service_principal_name[i]) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = samdb_msg_add_string(remote_ldb, tmp_ctx, msg, "servicePrincipalName", service_principal_name[i]); if (rtn == -1) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } } rtn = samdb_msg_add_string(remote_ldb, tmp_ctx, msg, "dNSHostName", dns_host_name); if (rtn == -1) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = samdb_replace(remote_ldb, tmp_ctx, msg); if (rtn != 0) { r->out.error_string = talloc_asprintf(r, "Failed to replace entries on %s", ldb_dn_get_linearized(msg->dn)); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } } /* DsCrackNames to find out the DN of the domain. */ r_crack_names.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT; r_crack_names.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779; names[0].str = talloc_asprintf(tmp_ctx, "%s\\", r->out.domain_name); if (!names[0].str) { r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } status = dcerpc_drsuapi_DsCrackNames(drsuapi_pipe, tmp_ctx, &r_crack_names); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", r->in.domain_name, dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code)); talloc_free(tmp_ctx); return status; } else { r->out.error_string = talloc_asprintf(r, "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", r->in.domain_name, nt_errstr(status)); talloc_free(tmp_ctx); return status; } } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result)); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } else if (*r_crack_names.out.level_out != 1 || !r_crack_names.out.ctr->ctr1 || r_crack_names.out.ctr->ctr1->count != 1 || !r_crack_names.out.ctr->ctr1->array[0].result_name || r_crack_names.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) { r->out.error_string = talloc_asprintf(r, "DsCrackNames failed"); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } /* Store the account DN. */ r->out.account_dn_str = account_dn_str; talloc_steal(r, account_dn_str); /* Store the domain DN. */ r->out.domain_dn_str = r_crack_names.out.ctr->ctr1->array[0].result_name; talloc_steal(r, r_crack_names.out.ctr->ctr1->array[0].result_name); /* Store the KVNO of the account, critical for some kerberos * operations */ r->out.kvno = ldb_msg_find_attr_as_uint(res->msgs[0], "msDS-KeyVersionNumber", 0); /* Store the account GUID. */ r->out.account_guid = samdb_result_guid(res->msgs[0], "objectGUID"); if (r->in.acct_type == ACB_SVRTRUST) { status = libnet_JoinSite(ctx, remote_ldb, r); } talloc_free(tmp_ctx); return status; }
static bool torture_ldb_dn(struct torture_context *torture) { TALLOC_CTX *mem_ctx = talloc_new(torture); struct ldb_context *ldb; struct ldb_dn *dn; struct ldb_dn *child_dn; struct ldb_dn *typo_dn; struct ldb_val val; torture_assert(torture, ldb = ldb_init(mem_ctx, torture->ev), "Failed to init ldb"); torture_assert_int_equal(torture, ldb_register_samba_handlers(ldb), 0, "Failed to register Samba handlers"); ldb_set_utf8_fns(ldb, NULL, wrap_casefold); /* Check behaviour of a normal DN */ torture_assert(torture, dn = ldb_dn_new(mem_ctx, ldb, NULL), "Failed to create a NULL DN"); torture_assert(torture, ldb_dn_validate(dn), "Failed to validate NULL DN"); torture_assert(torture, ldb_dn_add_base_fmt(dn, "dc=org"), "Failed to add base DN"); torture_assert(torture, ldb_dn_add_child_fmt(dn, "dc=samba"), "Failed to add base DN"); torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "dc=samba,dc=org", "linearized DN incorrect"); torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 0), "dc=samba,dc=org", "extended linearized DN incorrect"); /* Check child DN comparisons */ torture_assert(torture, child_dn = ldb_dn_new(mem_ctx, ldb, "CN=users,DC=SAMBA,DC=org"), "Failed to create child DN"); torture_assert(torture, ldb_dn_compare(dn, child_dn) != 0, "Comparison on dc=samba,dc=org and CN=users,DC=SAMBA,DC=org should != 0"); torture_assert(torture, ldb_dn_compare_base(child_dn, dn) != 0, "Base Comparison of CN=users,DC=SAMBA,DC=org and dc=samba,dc=org should != 0"); torture_assert(torture, ldb_dn_compare_base(dn, child_dn) == 0, "Base Comparison on dc=samba,dc=org and CN=users,DC=SAMBA,DC=org should == 0"); /* Check comparisons with a truncated DN */ torture_assert(torture, typo_dn = ldb_dn_new(mem_ctx, ldb, "c=samba,dc=org"), "Failed to create 'typo' DN"); torture_assert(torture, ldb_dn_compare(dn, typo_dn) != 0, "Comparison on dc=samba,dc=org and c=samba,dc=org should != 0"); torture_assert(torture, ldb_dn_compare_base(typo_dn, dn) != 0, "Base Comparison of c=samba,dc=org and dc=samba,dc=org should != 0"); torture_assert(torture, ldb_dn_compare_base(dn, typo_dn) != 0, "Base Comparison on dc=samba,dc=org and c=samba,dc=org should != 0"); /* Check DN based on MS-ADTS:3.1.1.5.1.2 Naming Constraints*/ torture_assert(torture, dn = ldb_dn_new(mem_ctx, ldb, "CN=New\nLine,DC=SAMBA,DC=org"), "Failed to create a DN with 0xA in it"); /* this is a warning until we work out how the DEL: CNs work */ if (ldb_dn_validate(dn) != false) { torture_warning(torture, "should have failed to validate a DN with 0xA in it"); } val = data_blob_const("CN=Zer\0,DC=SAMBA,DC=org", 23); torture_assert(torture, NULL == ldb_dn_from_ldb_val(mem_ctx, ldb, &val), "should fail to create a DN with 0x0 in it"); talloc_free(mem_ctx); return true; }
/* * find out Site specific stuff: * 1. Lookup the Site name. * 2. Add entry CN=<netbios name>,CN=Servers,CN=<site name>,CN=Sites,CN=Configuration,<domain dn>. * TODO: 3.) use DsAddEntry() to create CN=NTDS Settings,CN=<netbios name>,CN=Servers,CN=<site name>,... */ NTSTATUS libnet_JoinSite(struct libnet_context *ctx, struct ldb_context *remote_ldb, struct libnet_JoinDomain *libnet_r) { NTSTATUS status; TALLOC_CTX *tmp_ctx; struct libnet_JoinSite *r; struct ldb_dn *server_dn; struct ldb_message *msg; int rtn; const char *server_dn_str; const char *config_dn_str; struct nbt_name name; const char *dest_addr = NULL; tmp_ctx = talloc_named(libnet_r, 0, "libnet_JoinSite temp context"); if (!tmp_ctx) { libnet_r->out.error_string = NULL; return NT_STATUS_NO_MEMORY; } r = talloc(tmp_ctx, struct libnet_JoinSite); if (!r) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } make_nbt_name_client(&name, libnet_r->out.samr_binding->host); status = resolve_name(lp_resolve_context(ctx->lp_ctx), &name, r, &dest_addr, ctx->event_ctx); if (!NT_STATUS_IS_OK(status)) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return status; } /* Resolve the site name and AD DN's. */ r->in.dest_address = dest_addr; r->in.netbios_name = libnet_r->in.netbios_name; r->in.domain_dn_str = libnet_r->out.domain_dn_str; r->in.cldap_port = lp_cldap_port(ctx->lp_ctx); status = libnet_FindSite(tmp_ctx, ctx, r); if (!NT_STATUS_IS_OK(status)) { libnet_r->out.error_string = talloc_steal(libnet_r, r->out.error_string); talloc_free(tmp_ctx); return status; } config_dn_str = r->out.config_dn_str; server_dn_str = r->out.server_dn_str; /* Add entry CN=<netbios name>,CN=Servers,CN=<site name>,CN=Sites,CN=Configuration,<domain dn>. */ msg = ldb_msg_new(tmp_ctx); if (!msg) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = ldb_msg_add_string(msg, "objectClass", "server"); if (rtn != 0) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = ldb_msg_add_string(msg, "systemFlags", "50000000"); if (rtn != 0) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } rtn = ldb_msg_add_string(msg, "serverReference", libnet_r->out.account_dn_str); if (rtn != 0) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } server_dn = ldb_dn_new(tmp_ctx, remote_ldb, server_dn_str); if ( ! ldb_dn_validate(server_dn)) { libnet_r->out.error_string = talloc_asprintf(libnet_r, "Invalid server dn: %s", server_dn_str); talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } msg->dn = server_dn; rtn = ldb_add(remote_ldb, msg); if (rtn == LDB_ERR_ENTRY_ALREADY_EXISTS) { int i; /* make a 'modify' msg, and only for serverReference */ msg = ldb_msg_new(tmp_ctx); if (!msg) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } msg->dn = server_dn; rtn = ldb_msg_add_string(msg, "serverReference",libnet_r->out.account_dn_str); if (rtn != 0) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* mark all the message elements (should be just one) as LDB_FLAG_MOD_REPLACE */ for (i=0; i<msg->num_elements; i++) { msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; } rtn = ldb_modify(remote_ldb, msg); if (rtn != 0) { libnet_r->out.error_string = talloc_asprintf(libnet_r, "Failed to modify server entry %s: %s: %d", server_dn_str, ldb_errstring(remote_ldb), rtn); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } } else if (rtn != 0) { libnet_r->out.error_string = talloc_asprintf(libnet_r, "Failed to add server entry %s: %s: %d", server_dn_str, ldb_errstring(remote_ldb), rtn); talloc_free(tmp_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } DEBUG(0, ("We still need to perform a DsAddEntry() so that we can create the CN=NTDS Settings container.\n")); /* Store the server DN in libnet_r */ libnet_r->out.server_dn_str = server_dn_str; talloc_steal(libnet_r, server_dn_str); talloc_free(tmp_ctx); return NT_STATUS_OK; }
/* drsuapi_DsWriteAccountSpn */ WERROR dcesrv_drsuapi_DsWriteAccountSpn(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct drsuapi_DsWriteAccountSpn *r) { struct drsuapi_bind_state *b_state; struct dcesrv_handle *h; *r->out.level_out = r->in.level; DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); b_state = h->data; r->out.res = talloc(mem_ctx, union drsuapi_DsWriteAccountSpnResult); W_ERROR_HAVE_NO_MEMORY(r->out.res); switch (r->in.level) { case 1: { struct drsuapi_DsWriteAccountSpnRequest1 *req; struct ldb_message *msg; int count, i, ret; struct ldb_result *res; const char *attrs[] = { "servicePrincipalName", NULL }; struct ldb_message_element *el; unsigned spn_count=0; req = &r->in.req->req1; count = req->count; msg = ldb_msg_new(mem_ctx); if (msg == NULL) { return WERR_NOMEM; } msg->dn = ldb_dn_new(msg, b_state->sam_ctx, req->object_dn); if ( ! ldb_dn_validate(msg->dn)) { r->out.res->res1.status = WERR_OK; return WERR_OK; } /* load the existing SPNs, as these are * ignored for adds and deletes (see MS-DRSR * section 4.1.28.3) */ ret = ldb_search(b_state->sam_ctx, msg, &res, msg->dn, LDB_SCOPE_BASE, attrs, NULL); if (ret != LDB_SUCCESS) { DEBUG(0,("Failed to load existing SPNs on %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(b_state->sam_ctx))); r->out.res->res1.status = WERR_DS_OBJ_NOT_FOUND; return WERR_OK; } el = ldb_msg_find_element(res->msgs[0], "servicePrincipalName"); /* construct mods */ for (i = 0; i < count; i++) { bool found = false; int j; for (j=0; el && j<el->num_values; j++) { if (samdb_ldb_val_case_cmp(req->spn_names[i].str, &el->values[j]) == 0) { found = true; break; } } if ((req->operation == DRSUAPI_DS_SPN_OPERATION_ADD && found) || (req->operation == DRSUAPI_DS_SPN_OPERATION_DELETE && !found)) { continue; } ret = samdb_msg_add_string(b_state->sam_ctx, msg, msg, "servicePrincipalName", req->spn_names[i].str); if (ret != LDB_SUCCESS) { return WERR_NOMEM; } spn_count++; } if (msg->num_elements == 0) { DEBUG(2,("No SPNs need changing on %s\n", ldb_dn_get_linearized(msg->dn))); r->out.res->res1.status = WERR_OK; return WERR_OK; } for (i=0;i<msg->num_elements;i++) { switch (req->operation) { case DRSUAPI_DS_SPN_OPERATION_ADD: msg->elements[i].flags = LDB_FLAG_MOD_ADD; break; case DRSUAPI_DS_SPN_OPERATION_REPLACE: msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; break; case DRSUAPI_DS_SPN_OPERATION_DELETE: msg->elements[i].flags = LDB_FLAG_MOD_DELETE; break; } } /* Apply to database */ ret = ldb_modify(b_state->sam_ctx, msg); if (ret != 0) { DEBUG(0,("Failed to modify SPNs on %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(b_state->sam_ctx))); r->out.res->res1.status = WERR_ACCESS_DENIED; } else { DEBUG(2,("Modified %u SPNs on %s\n", spn_count, ldb_dn_get_linearized(msg->dn))); r->out.res->res1.status = WERR_OK; } return WERR_OK; } } return WERR_UNKNOWN_LEVEL; }
struct dsdb_dn *dsdb_dn_parse(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, const struct ldb_val *dn_blob, const char *dn_oid) { struct dsdb_dn *dsdb_dn; struct ldb_dn *dn; const char *data; size_t len; TALLOC_CTX *tmp_ctx; char *p1; char *p2; uint32_t blen; struct ldb_val bval; struct ldb_val dval; char *dn_str; enum dsdb_dn_format dn_format = dsdb_dn_oid_to_format(dn_oid); switch (dn_format) { case DSDB_INVALID_DN: return NULL; case DSDB_NORMAL_DN: { dn = ldb_dn_from_ldb_val(mem_ctx, ldb, dn_blob); if (!dn || !ldb_dn_validate(dn)) { talloc_free(dn); return NULL; } return dsdb_dn_construct_internal(mem_ctx, dn, data_blob_null, dn_format, dn_oid); } case DSDB_BINARY_DN: if (dn_blob->length < 2 || dn_blob->data[0] != 'B' || dn_blob->data[1] != ':') { return NULL; } break; case DSDB_STRING_DN: if (dn_blob->length < 2 || dn_blob->data[0] != 'S' || dn_blob->data[1] != ':') { return NULL; } break; default: return NULL; } if (dn_blob && dn_blob->data && (strlen((const char*)dn_blob->data) != dn_blob->length)) { /* The RDN must not contain a character with value 0x0 */ return NULL; } if (!dn_blob->data || dn_blob->length == 0) { return NULL; } tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return NULL; } data = (const char *)dn_blob->data; len = dn_blob->length - 2; p1 = talloc_strndup(tmp_ctx, (const char *)dn_blob->data + 2, len); if (!p1) { goto failed; } errno = 0; blen = strtoul(p1, &p2, 10); if (errno != 0) { DEBUG(10, (__location__ ": failed\n")); goto failed; } if (p2 == NULL) { DEBUG(10, (__location__ ": failed\n")); goto failed; } if (p2[0] != ':') { DEBUG(10, (__location__ ": failed\n")); goto failed; } len -= PTR_DIFF(p2,p1);//??? p1 = p2+1; len--; if (blen >= len) { DEBUG(10, (__location__ ": blen=%u len=%u\n", (unsigned)blen, (unsigned)len)); goto failed; } p2 = p1 + blen; if (p2[0] != ':') { DEBUG(10, (__location__ ": %s", p2)); goto failed; } dn_str = p2+1; switch (dn_format) { case DSDB_BINARY_DN: if ((blen % 2 != 0)) { DEBUG(10, (__location__ ": blen=%u - not an even number\n", (unsigned)blen)); goto failed; } if (blen >= 2) { bval.length = (blen/2)+1; bval.data = talloc_size(tmp_ctx, bval.length); if (bval.data == NULL) { DEBUG(10, (__location__ ": err\n")); goto failed; } bval.data[bval.length-1] = 0; bval.length = strhex_to_str((char *)bval.data, bval.length, p1, blen); if (bval.length != (blen / 2)) { DEBUG(10, (__location__ ": non hexidecimal characters found in binary prefix\n")); goto failed; } } else { bval = data_blob_null; } break; case DSDB_STRING_DN: bval = data_blob(p1, blen); break; default: /* never reached */ return NULL; } dval.data = (uint8_t *)dn_str; dval.length = strlen(dn_str); dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &dval); if (!dn || !ldb_dn_validate(dn)) { DEBUG(10, (__location__ ": err\n")); goto failed; } dsdb_dn = dsdb_dn_construct(mem_ctx, dn, bval, dn_oid); return dsdb_dn; failed: talloc_free(tmp_ctx); return NULL; }
static NTSTATUS torture_leave_ads_domain(struct torture_context *torture, TALLOC_CTX *mem_ctx, struct libnet_JoinDomain *libnet_r) { int rtn; TALLOC_CTX *tmp_ctx; struct ldb_dn *server_dn; struct ldb_context *ldb_ctx; char *remote_ldb_url; /* Check if we are a domain controller. If not, exit. */ if (!libnet_r->out.server_dn_str) { return NT_STATUS_OK; } tmp_ctx = talloc_named(mem_ctx, 0, "torture_leave temporary context"); if (!tmp_ctx) { libnet_r->out.error_string = NULL; return NT_STATUS_NO_MEMORY; } ldb_ctx = ldb_init(tmp_ctx, torture->ev); if (!ldb_ctx) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } /* Remove CN=Servers,... entry from the AD. */ server_dn = ldb_dn_new(tmp_ctx, ldb_ctx, libnet_r->out.server_dn_str); if (! ldb_dn_validate(server_dn)) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s", libnet_r->out.samr_binding->host); if (!remote_ldb_url) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_NO_MEMORY; } ldb_set_opaque(ldb_ctx, "credentials", cmdline_credentials); ldb_set_opaque(ldb_ctx, "loadparm", cmdline_lp_ctx); rtn = ldb_connect(ldb_ctx, remote_ldb_url, 0, NULL); if (rtn != 0) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } rtn = ldb_delete(ldb_ctx, server_dn); if (rtn != 0) { libnet_r->out.error_string = NULL; talloc_free(tmp_ctx); return NT_STATUS_UNSUCCESSFUL; } DEBUG(0, ("%s removed successfully.\n", libnet_r->out.server_dn_str)); talloc_free(tmp_ctx); return NT_STATUS_OK; }
int sysdb_upgrade_10(struct sysdb_ctx *sysdb, const char **ver) { TALLOC_CTX *tmp_ctx; int ret; struct ldb_result *res; struct ldb_message *msg; struct ldb_message *user; struct ldb_message_element *memberof_el; const char *name; struct ldb_dn *basedn; const char *filter = "(&(objectClass=user)(!(uidNumber=*))(memberOf=*))"; const char *attrs[] = { "name", "memberof", NULL }; int i, j; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { return ENOMEM; } basedn = ldb_dn_new_fmt(tmp_ctx, sysdb->ldb, SYSDB_TMPL_USER_BASE, sysdb->domain->name); if (basedn == NULL) { ret = EIO; goto done; } DEBUG(SSSDBG_CRIT_FAILURE, ("UPGRADING DB TO VERSION %s\n", SYSDB_VERSION_0_11)); ret = ldb_transaction_start(sysdb->ldb); if (ret != LDB_SUCCESS) { ret = EIO; goto done; } ret = ldb_search(sysdb->ldb, tmp_ctx, &res, basedn, LDB_SCOPE_SUBTREE, attrs, "%s", filter); if (ret != LDB_SUCCESS) { ret = EIO; goto done; } for (i = 0; i < res->count; i++) { user = res->msgs[i]; memberof_el = ldb_msg_find_element(user, "memberof"); name = ldb_msg_find_attr_as_string(user, "name", NULL); if (name == NULL) { ret = EIO; goto done; } for (j = 0; j < memberof_el->num_values; j++) { msg = ldb_msg_new(tmp_ctx); if (msg == NULL) { ret = ENOMEM; goto done; } msg->dn = ldb_dn_from_ldb_val(tmp_ctx, sysdb->ldb, &memberof_el->values[j]); if (msg->dn == NULL) { ret = ENOMEM; goto done; } if (!ldb_dn_validate(msg->dn)) { DEBUG(SSSDBG_MINOR_FAILURE, ("DN validation failed during " "upgrade: [%s]\n", memberof_el->values[j].data)); talloc_zfree(msg); continue; } ret = ldb_msg_add_empty(msg, "ghost", LDB_FLAG_MOD_ADD, NULL); if (ret != LDB_SUCCESS) { ret = ENOMEM; goto done; } ret = ldb_msg_add_string(msg, "ghost", name); if (ret != LDB_SUCCESS) { ret = ENOMEM; goto done; } ret = ldb_msg_add_empty(msg, "member", LDB_FLAG_MOD_DELETE, NULL); if (ret != LDB_SUCCESS) { ret = ENOMEM; goto done; } ret = ldb_msg_add_string(msg, "member", ldb_dn_get_linearized(user->dn)); if (ret != LDB_SUCCESS) { ret = ENOMEM; goto done; } ret = ldb_modify(sysdb->ldb, msg); talloc_zfree(msg); if (ret != LDB_SUCCESS) { ret = sysdb_error_to_errno(ret); goto done; } } ret = ldb_delete(sysdb->ldb, user->dn); if (ret != LDB_SUCCESS) { ret = sysdb_error_to_errno(ret); goto done; } } /* conversion done, upgrade version number */ msg = ldb_msg_new(tmp_ctx); if (!msg) { ret = ENOMEM; goto done; } msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_BASE); if (!msg->dn) { ret = ENOMEM; goto done; } ret = ldb_msg_add_empty(msg, "version", LDB_FLAG_MOD_REPLACE, NULL); if (ret != LDB_SUCCESS) { ret = ENOMEM; goto done; } ret = ldb_msg_add_string(msg, "version", SYSDB_VERSION_0_11); if (ret != LDB_SUCCESS) { ret = ENOMEM; goto done; } ret = ldb_modify(sysdb->ldb, msg); if (ret != LDB_SUCCESS) { ret = sysdb_error_to_errno(ret); goto done; } ret = EOK; done: ret = finish_upgrade(ret, sysdb->ldb, SYSDB_VERSION_0_11, ver); talloc_free(tmp_ctx); return ret; }
/* load the partitions list based on replicated NC attributes in our NTDSDSA object */ WERROR dreplsrv_load_partitions(struct dreplsrv_service *s) { WERROR status; static const char *attrs[] = { "hasMasterNCs", "msDs-hasMasterNCs", "hasPartialReplicaNCs", "msDS-HasFullReplicaNCs", NULL }; unsigned int a; int ret; TALLOC_CTX *tmp_ctx; struct ldb_result *res; struct ldb_message_element *el; struct ldb_dn *ntds_dn; tmp_ctx = talloc_new(s); W_ERROR_HAVE_NO_MEMORY(tmp_ctx); ntds_dn = samdb_ntds_settings_dn(s->samdb); if (!ntds_dn) { DEBUG(1,(__location__ ": Unable to find ntds_dn: %s\n", ldb_errstring(s->samdb))); talloc_free(tmp_ctx); return WERR_DS_DRA_INTERNAL_ERROR; } ret = dsdb_search_dn(s->samdb, tmp_ctx, &res, ntds_dn, attrs, DSDB_SEARCH_SHOW_EXTENDED_DN); if (ret != LDB_SUCCESS) { DEBUG(1,("Searching for hasMasterNCs in NTDS DN failed: %s\n", ldb_errstring(s->samdb))); talloc_free(tmp_ctx); return WERR_DS_DRA_INTERNAL_ERROR; } for (a=0; attrs[a]; a++) { int i; el = ldb_msg_find_element(res->msgs[0], attrs[a]); if (el == NULL) { continue; } for (i=0; i<el->num_values; i++) { struct ldb_dn *pdn; struct dreplsrv_partition *p, *tp; bool found; pdn = ldb_dn_from_ldb_val(tmp_ctx, s->samdb, &el->values[i]); if (pdn == NULL) { talloc_free(tmp_ctx); return WERR_DS_DRA_INTERNAL_ERROR; } if (!ldb_dn_validate(pdn)) { return WERR_DS_DRA_INTERNAL_ERROR; } p = talloc_zero(s, struct dreplsrv_partition); W_ERROR_HAVE_NO_MEMORY(p); p->dn = talloc_steal(p, pdn); p->service = s; if (strcasecmp(attrs[a], "hasPartialReplicaNCs") == 0) { p->partial_replica = true; } else if (strcasecmp(attrs[a], "msDS-HasFullReplicaNCs") == 0) { p->rodc_replica = true; } /* Do not add partitions more than once */ found = false; for (tp = s->partitions; tp; tp = tp->next) { if (ldb_dn_compare(tp->dn, p->dn) == 0) { found = true; break; } } if (found) { talloc_free(p); continue; } DLIST_ADD(s->partitions, p); DEBUG(2, ("dreplsrv_partition[%s] loaded\n", ldb_dn_get_linearized(p->dn))); } } talloc_free(tmp_ctx); status = dreplsrv_refresh_partitions(s); W_ERROR_NOT_OK_RETURN(status); return WERR_OK; }
/** \details Initialize and create a message object \param mem_ctx pointer to the memory context to use for allocation \param ldb_ctx pointer to the ldb context \param messageID the identifier of the message to create \param folderID the identifier of the folder where the message is created \param message_object pointer on pointer to the message object to return \return MAPI_E_SUCCESS on success, otherwise MAPI error */ _PUBLIC_ enum MAPISTATUS openchangedb_message_create(TALLOC_CTX *mem_ctx, struct ldb_context *ldb_ctx, uint64_t messageID, uint64_t folderID, bool fai, void **message_object) { enum MAPISTATUS retval; struct openchangedb_message *msg; struct ldb_dn *basedn; char *dn; char *parentDN; char *mailboxDN; int i; /* Sanity checks */ OPENCHANGE_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!message_object, MAPI_E_NOT_INITIALIZED, NULL); /* Retrieve distinguishedName of parent folder */ retval = openchangedb_get_distinguishedName(mem_ctx, ldb_ctx, folderID, &parentDN); OPENCHANGE_RETVAL_IF(retval, retval, NULL); /* Retrieve mailboxDN of parent folder */ retval = openchangedb_get_mailboxDN(mem_ctx, ldb_ctx, folderID, &mailboxDN); if (retval) { mailboxDN = NULL; } dn = talloc_asprintf(mem_ctx, "CN=%"PRIu64",%s", messageID, parentDN); OPENCHANGE_RETVAL_IF(!dn, MAPI_E_NOT_ENOUGH_MEMORY, NULL); basedn = ldb_dn_new(mem_ctx, ldb_ctx, dn); talloc_free(dn); OPENCHANGE_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, NULL); msg = talloc_zero(mem_ctx, struct openchangedb_message); OPENCHANGE_RETVAL_IF(!msg, MAPI_E_NOT_ENOUGH_MEMORY, NULL); msg->status = OPENCHANGEDB_MESSAGE_CREATE; msg->folderID = folderID; msg->messageID = messageID; msg->ldb_ctx = ldb_ctx; msg->msg = NULL; msg->res = NULL; msg->msg = ldb_msg_new((TALLOC_CTX *)msg); OPENCHANGE_RETVAL_IF(!msg->msg, MAPI_E_NOT_ENOUGH_MEMORY, msg); msg->msg->dn = ldb_dn_copy((TALLOC_CTX *)msg->msg, basedn); /* Add openchangedb required attributes */ ldb_msg_add_string(msg->msg, "objectClass", fai ? "faiMessage" : "systemMessage"); ldb_msg_add_fmt(msg->msg, "cn", "%"PRIu64, messageID); ldb_msg_add_fmt(msg->msg, "PidTagParentFolderId", "%"PRIu64, folderID); ldb_msg_add_fmt(msg->msg, "PidTagMessageId", "%"PRIu64, messageID); ldb_msg_add_fmt(msg->msg, "distinguishedName", "%s", ldb_dn_get_linearized(msg->msg->dn)); if (mailboxDN) { ldb_msg_add_string(msg->msg, "mailboxDN", mailboxDN); } /* Add required properties as described in [MS_OXCMSG] 3.2.5.2 */ ldb_msg_add_string(msg->msg, "PidTagDisplayBcc", ""); ldb_msg_add_string(msg->msg, "PidTagDisplayCc", ""); ldb_msg_add_string(msg->msg, "PidTagDisplayTo", ""); /* PidTagMessageSize */ /* PidTagSecurityDescriptor */ /* ldb_msg_add_string(msg->msg, "PidTagCreationTime", ""); */ /* ldb_msg_add_string(msg->msg, "PidTagLastModificationTime", ""); */ /* PidTagSearchKey */ /* PidTagMessageLocalId */ /* PidTagCreatorName */ /* PidTagCreatorEntryId */ ldb_msg_add_fmt(msg->msg, "PidTagHasNamedProperties", "%d", 0x0); /* PidTagLocaleId same as PidTagMessageLocaleId */ /* PidTagLocalCommitTime same as PidTagCreationTime */ /* Set LDB flag */ for (i = 0; i < msg->msg->num_elements; i++) { msg->msg->elements[i].flags = LDB_FLAG_MOD_ADD; } *message_object = (void *)msg; return MAPI_E_SUCCESS; }
static int ldapsrv_load_limits(struct ldapsrv_connection *conn) { TALLOC_CTX *tmp_ctx; const char *attrs[] = { "configurationNamingContext", NULL }; const char *attrs2[] = { "lDAPAdminLimits", NULL }; struct ldb_message_element *el; struct ldb_result *res = NULL; struct ldb_dn *basedn; struct ldb_dn *conf_dn; struct ldb_dn *policy_dn; int i,ret; /* set defaults limits in case of failure */ conn->limits.initial_timeout = 120; conn->limits.conn_idle_time = 900; conn->limits.max_page_size = 1000; conn->limits.search_timeout = 120; tmp_ctx = talloc_new(conn); if (tmp_ctx == NULL) { return -1; } basedn = ldb_dn_new(tmp_ctx, conn->ldb, NULL); if ( ! ldb_dn_validate(basedn)) { goto failed; } ret = ldb_search(conn->ldb, tmp_ctx, &res, basedn, LDB_SCOPE_BASE, attrs, NULL); if (ret != LDB_SUCCESS) { goto failed; } if (res->count != 1) { goto failed; } conf_dn = ldb_msg_find_attr_as_dn(conn->ldb, tmp_ctx, res->msgs[0], "configurationNamingContext"); if (conf_dn == NULL) { goto failed; } policy_dn = ldb_dn_copy(tmp_ctx, conf_dn); ldb_dn_add_child_fmt(policy_dn, "CN=Default Query Policy,CN=Query-Policies,CN=Directory Service,CN=Windows NT,CN=Services"); if (policy_dn == NULL) { goto failed; } ret = ldb_search(conn->ldb, tmp_ctx, &res, policy_dn, LDB_SCOPE_BASE, attrs2, NULL); if (ret != LDB_SUCCESS) { goto failed; } if (res->count != 1) { goto failed; } el = ldb_msg_find_element(res->msgs[0], "lDAPAdminLimits"); if (el == NULL) { goto failed; } for (i = 0; i < el->num_values; i++) { char policy_name[256]; int policy_value, s; s = sscanf((const char *)el->values[i].data, "%255[^=]=%d", policy_name, &policy_value); if (ret != 2 || policy_value == 0) continue; if (strcasecmp("InitRecvTimeout", policy_name) == 0) { conn->limits.initial_timeout = policy_value; continue; } if (strcasecmp("MaxConnIdleTime", policy_name) == 0) { conn->limits.conn_idle_time = policy_value; continue; } if (strcasecmp("MaxPageSize", policy_name) == 0) { conn->limits.max_page_size = policy_value; continue; } if (strcasecmp("MaxQueryDuration", policy_name) == 0) { conn->limits.search_timeout = policy_value; continue; } } return 0; failed: DEBUG(0, ("Failed to load ldap server query policies\n")); talloc_free(tmp_ctx); return -1; }
/* 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; }
static bool torture_ldb_dn(struct torture_context *torture) { TALLOC_CTX *mem_ctx = talloc_new(torture); struct ldb_context *ldb; struct ldb_dn *dn; struct ldb_dn *child_dn; struct ldb_dn *typo_dn; torture_assert(torture, ldb = ldb_init(mem_ctx, torture->ev), "Failed to init ldb"); torture_assert_int_equal(torture, ldb_register_samba_handlers(ldb), 0, "Failed to register Samba handlers"); ldb_set_utf8_fns(ldb, NULL, wrap_casefold); /* Check behaviour of a normal DN */ torture_assert(torture, dn = ldb_dn_new(mem_ctx, ldb, NULL), "Failed to create a NULL DN"); torture_assert(torture, ldb_dn_validate(dn), "Failed to validate NULL DN"); torture_assert(torture, ldb_dn_add_base_fmt(dn, "dc=org"), "Failed to add base DN"); torture_assert(torture, ldb_dn_add_child_fmt(dn, "dc=samba"), "Failed to add base DN"); torture_assert_str_equal(torture, ldb_dn_get_linearized(dn), "dc=samba,dc=org", "linearized DN incorrect"); torture_assert_str_equal(torture, ldb_dn_get_extended_linearized(mem_ctx, dn, 0), "dc=samba,dc=org", "extended linearized DN incorrect"); /* Check child DN comparisons */ torture_assert(torture, child_dn = ldb_dn_new(mem_ctx, ldb, "CN=users,DC=SAMBA,DC=org"), "Failed to create child DN"); torture_assert(torture, ldb_dn_compare(dn, child_dn) != 0, "Comparison on dc=samba,dc=org and CN=users,DC=SAMBA,DC=org should != 0"); torture_assert(torture, ldb_dn_compare_base(child_dn, dn) != 0, "Base Comparison of CN=users,DC=SAMBA,DC=org and dc=samba,dc=org should != 0"); torture_assert(torture, ldb_dn_compare_base(dn, child_dn) == 0, "Base Comparison on dc=samba,dc=org and CN=users,DC=SAMBA,DC=org should == 0"); /* Check comparisons with a truncated DN */ torture_assert(torture, typo_dn = ldb_dn_new(mem_ctx, ldb, "c=samba,dc=org"), "Failed to create 'typo' DN"); torture_assert(torture, ldb_dn_compare(dn, typo_dn) != 0, "Comparison on dc=samba,dc=org and c=samba,dc=org should != 0"); torture_assert(torture, ldb_dn_compare_base(typo_dn, dn) != 0, "Base Comparison of c=samba,dc=org and dc=samba,dc=org should != 0"); torture_assert(torture, ldb_dn_compare_base(dn, typo_dn) != 0, "Base Comparison on dc=samba,dc=org and c=samba,dc=org should != 0"); talloc_free(mem_ctx); return true; }
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 bool torture_ldb_dn_invalid_extended(struct torture_context *torture) { TALLOC_CTX *mem_ctx = talloc_new(torture); struct ldb_context *ldb; struct ldb_dn *dn; const char *dn_str = "cn=admin,cn=users,dc=samba,dc=org"; torture_assert(torture, ldb = ldb_init(mem_ctx, torture->ev), "Failed to init ldb"); torture_assert_int_equal(torture, ldb_register_samba_handlers(ldb), 0, "Failed to register Samba handlers"); ldb_set_utf8_fns(ldb, NULL, wrap_casefold); /* Check behaviour of a normal DN */ torture_assert(torture, dn = ldb_dn_new(mem_ctx, ldb, "samba,dc=org"), "Failed to create a 'normal' invalid DN"); torture_assert(torture, ldb_dn_validate(dn) == false, "should have failed to validate 'normal' invalid DN"); /* Now make an extended DN */ torture_assert(torture, dn = ldb_dn_new_fmt(mem_ctx, ldb, "<PID=%s>;%s", sid, dn_str), "Failed to create an invalid 'extended' DN"); torture_assert(torture, ldb_dn_validate(dn) == false, "should have failed to validate 'extended' DN"); torture_assert(torture, dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>%s", sid, dn_str), "Failed to create an invalid 'extended' DN"); torture_assert(torture, ldb_dn_validate(dn) == false, "should have failed to validate 'extended' DN"); torture_assert(torture, dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>;", sid), "Failed to create an invalid 'extended' DN"); torture_assert(torture, ldb_dn_validate(dn) == false, "should have failed to validate 'extended' DN"); torture_assert(torture, dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=%s>;", hex_sid), "Failed to create an invalid 'extended' DN"); torture_assert(torture, ldb_dn_validate(dn) == false, "should have failed to validate 'extended' DN"); torture_assert(torture, dn = ldb_dn_new_fmt(mem_ctx, ldb, "<SID=%s>;", hex_guid), "Failed to create an invalid 'extended' DN"); torture_assert(torture, ldb_dn_validate(dn) == false, "should have failed to validate 'extended' DN"); torture_assert(torture, dn = ldb_dn_new_fmt(mem_ctx, ldb, "<SID=%s>;", guid), "Failed to create an invalid 'extended' DN"); torture_assert(torture, ldb_dn_validate(dn) == false, "should have failed to validate 'extended' DN"); torture_assert(torture, dn = ldb_dn_new_fmt(mem_ctx, ldb, "<GUID=>"), "Failed to create an invalid 'extended' DN"); torture_assert(torture, ldb_dn_validate(dn) == false, "should have failed to validate 'extended' DN"); return true; }
/* return false if the request is still in progress * return true if the request is completed */ static bool lldb_parse_result(struct lldb_context *ac, LDAPMessage *result) { struct ldb_context *ldb; struct lldb_private *lldb = ac->lldb; LDAPControl **serverctrlsp = NULL; char **referralsp = NULL; char *matcheddnp = NULL; char *errmsgp = NULL; LDAPMessage *msg; int type; struct ldb_message *ldbmsg; char *referral; bool callback_failed; bool request_done; bool lret; unsigned int i; int ret; ldb = ldb_module_get_ctx(ac->module); type = ldap_msgtype(result); callback_failed = false; request_done = false; switch (type) { case LDAP_RES_SEARCH_ENTRY: msg = ldap_first_entry(lldb->ldap, result); if (msg != NULL) { BerElement *berptr = NULL; char *attr, *dn; ldbmsg = ldb_msg_new(ac); if (!ldbmsg) { ldb_oom(ldb); ret = LDB_ERR_OPERATIONS_ERROR; break; } dn = ldap_get_dn(lldb->ldap, msg); if (!dn) { ldb_oom(ldb); talloc_free(ldbmsg); ret = LDB_ERR_OPERATIONS_ERROR; break; } ldbmsg->dn = ldb_dn_new(ldbmsg, ldb, dn); if ( ! ldb_dn_validate(ldbmsg->dn)) { ldb_asprintf_errstring(ldb, "Invalid DN '%s' in reply", dn); talloc_free(ldbmsg); ret = LDB_ERR_OPERATIONS_ERROR; ldap_memfree(dn); break; } ldap_memfree(dn); ldbmsg->num_elements = 0; ldbmsg->elements = NULL; /* loop over all attributes */ for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr); attr; attr=ldap_next_attribute(lldb->ldap, msg, berptr)) { struct berval **bval; bval = ldap_get_values_len(lldb->ldap, msg, attr); if (bval) { lldb_add_msg_attr(ldb, ldbmsg, attr, bval); ldap_value_free_len(bval); } } if (berptr) ber_free(berptr, 0); ret = ldb_module_send_entry(ac->req, ldbmsg, NULL /* controls not yet supported */); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "entry send failed: %s", ldb_errstring(ldb)); callback_failed = true; } } else { ret = LDB_ERR_OPERATIONS_ERROR; } break; case LDAP_RES_SEARCH_REFERENCE: ret = ldap_parse_reference(lldb->ldap, result, &referralsp, &serverctrlsp, 0); if (ret != LDAP_SUCCESS) { ldb_asprintf_errstring(ldb, "ldap reference parse error: %s : %s", ldap_err2string(ret), errmsgp); ret = LDB_ERR_OPERATIONS_ERROR; break; } if (referralsp == NULL) { ldb_asprintf_errstring(ldb, "empty ldap referrals list"); ret = LDB_ERR_PROTOCOL_ERROR; break; } for (i = 0; referralsp[i]; i++) { referral = talloc_strdup(ac, referralsp[i]); ret = ldb_module_send_referral(ac->req, referral); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "referral send failed: %s", ldb_errstring(ldb)); callback_failed = true; break; } } break; case LDAP_RES_SEARCH_RESULT: case LDAP_RES_MODIFY: case LDAP_RES_ADD: case LDAP_RES_DELETE: case LDAP_RES_MODDN: if (ldap_parse_result(lldb->ldap, result, &ret, &matcheddnp, &errmsgp, &referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) { ret = LDB_ERR_OPERATIONS_ERROR; } if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "ldap parse error for type %d: %s : %s", type, ldap_err2string(ret), errmsgp); break; } if (serverctrlsp != NULL) { /* FIXME: transform the LDAPControl list into an ldb_control one */ ac->controls = NULL; } request_done = true; break; default: ldb_asprintf_errstring(ldb, "unknown ldap return type: %d", type); ret = LDB_ERR_PROTOCOL_ERROR; break; } if (ret != LDB_SUCCESS) { /* if the callback failed the caller will have freed the * request. Just return and don't try to use it */ if (callback_failed) { /* tell lldb_wait to remove the request from the * queue */ lret = true; goto free_and_return; } request_done = true; } if (request_done) { lldb_request_done(ac, ac->controls, ret); lret = true; goto free_and_return; } lret = false; free_and_return: if (matcheddnp) ldap_memfree(matcheddnp); if (errmsgp && *errmsgp) { ldb_set_errstring(ldb, errmsgp); } if (errmsgp) { ldap_memfree(errmsgp); } if (referralsp) ldap_value_free(referralsp); if (serverctrlsp) ldap_controls_free(serverctrlsp); ldap_msgfree(result); return lret; }