From: Stefan Metzmacher Date: Fri, 14 Mar 2025 08:30:03 +0000 (+0100) Subject: libcli/security: split trust_forest_info_* functions into samba-security-trusts X-Git-Tag: tevent-0.17.0~405 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2e52c4e8a56f659edd4fce8e4c964f193266f13d;p=thirdparty%2Fsamba.git libcli/security: split trust_forest_info_* functions into samba-security-trusts This will avoid dependency loops in following commits. Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme --- diff --git a/libcli/lsarpc/util_lsarpc.c b/libcli/lsarpc/util_lsarpc.c index 2a5752b4610..96c98487a7e 100644 --- a/libcli/lsarpc/util_lsarpc.c +++ b/libcli/lsarpc/util_lsarpc.c @@ -18,11 +18,9 @@ */ #include "includes.h" -#include "lib/util/dns_cmp.h" #include "../librpc/gen_ndr/ndr_drsblobs.h" #include "../librpc/gen_ndr/ndr_lsa.h" #include "libcli/lsarpc/util_lsarpc.h" -#include "libcli/security/dom_sid.h" static NTSTATUS ai_array_2_trust_domain_info_buffer(TALLOC_CTX *mem_ctx, uint32_t count, @@ -359,948 +357,3 @@ NTSTATUS auth_info_2_auth_blob(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } - -static NTSTATUS trust_forest_record_from_lsa(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustRecord2 *lftr, - struct ForestTrustInfoRecord *ftr) -{ - struct ForestTrustString *str = NULL; - const struct lsa_StringLarge *lstr = NULL; - const struct lsa_ForestTrustDomainInfo *linfo = NULL; - struct ForestTrustDataDomainInfo *info = NULL; - DATA_BLOB blob = { .length = 0, }; - - if (lftr == NULL) { - return NT_STATUS_INVALID_PARAMETER; - } - - ftr->flags = lftr->flags; - ftr->timestamp = lftr->time; - - switch (lftr->type) { - case LSA_FOREST_TRUST_TOP_LEVEL_NAME: - ftr->type = FOREST_TRUST_TOP_LEVEL_NAME; - - lstr = &lftr->forest_trust_data.top_level_name; - str = &ftr->data.name; - - str->string = talloc_strdup(mem_ctx, lstr->string); - if (str->string == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: - ftr->type = FOREST_TRUST_TOP_LEVEL_NAME_EX; - - lstr = &lftr->forest_trust_data.top_level_name_ex; - str = &ftr->data.name; - - str->string = talloc_strdup(mem_ctx, lstr->string); - if (str->string == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_DOMAIN_INFO: - ftr->type = FOREST_TRUST_DOMAIN_INFO; - - linfo = &lftr->forest_trust_data.domain_info; - info = &ftr->data.info; - - if (linfo->domain_sid == NULL) { - return NT_STATUS_INVALID_PARAMETER; - } - info->sid = *linfo->domain_sid; - - lstr = &linfo->dns_domain_name; - str = &info->dns_name; - str->string = talloc_strdup(mem_ctx, lstr->string); - if (str->string == NULL) { - return NT_STATUS_NO_MEMORY; - } - - lstr = &linfo->netbios_domain_name; - str = &info->netbios_name; - str->string = talloc_strdup(mem_ctx, lstr->string); - if (str->string == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_BINARY_DATA: - ftr->type = FOREST_TRUST_BINARY_DATA; - - blob = data_blob_talloc_named(mem_ctx, - lftr->forest_trust_data.data.data, - lftr->forest_trust_data.data.length, - "BINARY_DATA"); - if (blob.length != lftr->forest_trust_data.data.length) { - return NT_STATUS_NO_MEMORY; - } - ftr->data.binary.data = blob.data; - ftr->data.binary.size = blob.length; - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_SCANNER_INFO: - ftr->type = FOREST_TRUST_SCANNER_INFO; - - linfo = &lftr->forest_trust_data.scanner_info; - info = &ftr->data.scanner_info.info; - - ftr->data.scanner_info.sub_type = FOREST_TRUST_SCANNER_INFO; - - if (linfo->domain_sid != NULL) { - info->sid = *linfo->domain_sid; - } else { - info->sid = (struct dom_sid) { .sid_rev_num = 0, }; - } - - lstr = &linfo->dns_domain_name; - str = &info->dns_name; - str->string = talloc_strdup(mem_ctx, lstr->string); - if (str->string == NULL) { - return NT_STATUS_NO_MEMORY; - } - - lstr = &linfo->netbios_domain_name; - str = &info->netbios_name; - str->string = talloc_strdup(mem_ctx, lstr->string); - if (str->string == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; - } - - return NT_STATUS_NOT_SUPPORTED; -} - -static NTSTATUS trust_forest_record_lsa_resolve_binary(TALLOC_CTX *mem_ctx, - uint32_t flags, - NTTIME time, - const struct lsa_ForestTrustBinaryData *binary, - struct lsa_ForestTrustRecord2 *lftr2) -{ - enum ForestTrustInfoRecordType sub_type = FOREST_TRUST_BINARY_DATA; - DATA_BLOB blob = { .length = 0, }; - - if (binary == NULL) { - return NT_STATUS_INVALID_PARAMETER; - } - - /* - * Note 'binary' may points to - * lftr2->forest_trust_data.data - * - * So we remember the relevant - * information in blob and clear - * the binary pointer in order - * to avoid touching it again. - * - * Because we likely change - * the lftr2->forest_trust_data union - */ - blob.data = binary->data; - blob.length = binary->length; - binary = NULL; - - /* - * We need at least size and subtype - */ - if (blob.length < 5) { - return NT_STATUS_INVALID_PARAMETER; - } - - sub_type = PULL_LE_U8(blob.data, 4); - - /* - * Only levels above LSA_FOREST_TRUST_DOMAIN_INFO - * are handled as binary. - */ - if (sub_type <= FOREST_TRUST_BINARY_DATA) { - return NT_STATUS_INVALID_PARAMETER; - } - - lftr2->flags = flags; - lftr2->time = time; - - /* - * Depending if the sub_type is wellknown the information is upgraded, - * currently only for the LSA_FOREST_TRUST_SCANNER_INFO records. - */ - - if (sub_type == FOREST_TRUST_SCANNER_INFO) { - struct lsa_ForestTrustDomainInfo *d_sdi = NULL; - union ForestTrustData fta = { .unknown = { .size = 0, }, }; - const struct ForestTrustDataDomainInfo *s_sdi = NULL; - enum ndr_err_code ndr_err; - - ndr_err = ndr_pull_union_blob(&blob, - mem_ctx, - &fta, - FOREST_TRUST_SCANNER_INFO, - (ndr_pull_flags_fn_t)ndr_pull_ForestTrustData); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - if (fta.scanner_info.sub_type != FOREST_TRUST_SCANNER_INFO) { - return NT_STATUS_INVALID_PARAMETER; - } - - s_sdi = &fta.scanner_info.info; - d_sdi = &lftr2->forest_trust_data.scanner_info; - - d_sdi->dns_domain_name.string = s_sdi->dns_name.string; - d_sdi->netbios_domain_name.string = s_sdi->netbios_name.string; - - if (s_sdi->sid_size != 0) { - d_sdi->domain_sid = dom_sid_dup(mem_ctx, - &s_sdi->sid); - if (d_sdi->domain_sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - } else { - d_sdi->domain_sid = NULL; - } - - lftr2->type = LSA_FOREST_TRUST_SCANNER_INFO; - - return NT_STATUS_OK; - } - - /* - * In all other cases lftr->type is downgraded to - * LSA_FOREST_TRUST_BINARY_DATA. - */ - - lftr2->type = LSA_FOREST_TRUST_BINARY_DATA; - lftr2->forest_trust_data.data.data = blob.data; - lftr2->forest_trust_data.data.length = blob.length; - - return NT_STATUS_OK; -} - -static NTSTATUS trust_forest_record_lsa_1to2(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustRecord *lftr, - struct lsa_ForestTrustRecord2 *lftr2) -{ - const struct lsa_ForestTrustBinaryData *binary = NULL; - - if (lftr == NULL) { - return NT_STATUS_INVALID_PARAMETER; - } - - lftr2->flags = lftr->flags; - lftr2->time = lftr->time; - - switch (lftr->type) { - case LSA_FOREST_TRUST_TOP_LEVEL_NAME: - lftr2->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME; - lftr2->forest_trust_data.top_level_name = - lftr->forest_trust_data.top_level_name; - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: - lftr2->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX; - lftr2->forest_trust_data.top_level_name_ex = - lftr->forest_trust_data.top_level_name_ex; - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_DOMAIN_INFO: - lftr2->type = LSA_FOREST_TRUST_DOMAIN_INFO; - lftr2->forest_trust_data.domain_info = - lftr->forest_trust_data.domain_info; - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_BINARY_DATA: - case LSA_FOREST_TRUST_SCANNER_INFO: - /* just to avoid the missing enum switch warning */ - break; - } - - /* - * All levels above LSA_FOREST_TRUST_DOMAIN_INFO are handled as binary. - * - * Depending if the sub_type is wellknown the information is upgraded, - * currently only for the LSA_FOREST_TRUST_SCANNER_INFO records. - * - * In all other cases lftr->type is downgraded to - * LSA_FOREST_TRUST_BINARY_DATA. - */ - - binary = &lftr->forest_trust_data.data; - - return trust_forest_record_lsa_resolve_binary(mem_ctx, - lftr->flags, - lftr->time, - binary, - lftr2); -} - -NTSTATUS trust_forest_info_from_lsa(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustInformation *lfti, - struct ForestTrustInfo **_fti) -{ - struct ForestTrustInfo *fti; - uint32_t i; - - *_fti = NULL; - - fti = talloc_zero(mem_ctx, struct ForestTrustInfo); - if (fti == NULL) { - return NT_STATUS_NO_MEMORY; - } - - fti->version = 1; - fti->count = lfti->count; - fti->records = talloc_zero_array(fti, - struct ForestTrustInfoRecordArmor, - fti->count); - if (fti->records == NULL) { - TALLOC_FREE(fti); - return NT_STATUS_NO_MEMORY; - } - - for (i = 0; i < fti->count; i++) { - const struct lsa_ForestTrustRecord *lftr = lfti->entries[i]; - struct lsa_ForestTrustRecord2 lftr2 = { .flags = 0, }; - struct ForestTrustInfoRecord *ftr = &fti->records[i].record; - TALLOC_CTX *frame = talloc_stackframe(); - NTSTATUS status; - - status = trust_forest_record_lsa_1to2(frame, - lftr, - &lftr2); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(frame); - TALLOC_FREE(fti); - return status; - } - - status = trust_forest_record_from_lsa(fti->records, - &lftr2, - ftr); - TALLOC_FREE(frame); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(fti); - return status; - } - } - - *_fti = fti; - return NT_STATUS_OK; -} - -static NTSTATUS trust_forest_record_to_lsa(TALLOC_CTX *mem_ctx, - const struct ForestTrustInfoRecord *ftr, - struct lsa_ForestTrustRecord2 *lftr) -{ - const struct ForestTrustString *str = NULL; - struct lsa_StringLarge *lstr = NULL; - const struct ForestTrustDataDomainInfo *info = NULL; - struct lsa_ForestTrustDomainInfo *linfo = NULL; - DATA_BLOB blob = { .length = 0, }; - - lftr->flags = ftr->flags; - lftr->time = ftr->timestamp; - - switch (ftr->type) { - case FOREST_TRUST_TOP_LEVEL_NAME: - lftr->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME; - - lstr = &lftr->forest_trust_data.top_level_name; - str = &ftr->data.name; - - lstr->string = talloc_strdup(mem_ctx, str->string); - if (lstr->string == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; - - case FOREST_TRUST_TOP_LEVEL_NAME_EX: - lftr->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX; - - lstr = &lftr->forest_trust_data.top_level_name_ex; - str = &ftr->data.name; - - lstr->string = talloc_strdup(mem_ctx, str->string); - if (lstr->string == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; - - case FOREST_TRUST_DOMAIN_INFO: - lftr->type = LSA_FOREST_TRUST_DOMAIN_INFO; - - linfo = &lftr->forest_trust_data.domain_info; - info = &ftr->data.info; - - linfo->domain_sid = dom_sid_dup(mem_ctx, &info->sid); - if (linfo->domain_sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - - lstr = &linfo->dns_domain_name; - str = &info->dns_name; - lstr->string = talloc_strdup(mem_ctx, str->string); - if (lstr->string == NULL) { - return NT_STATUS_NO_MEMORY; - } - - lstr = &linfo->netbios_domain_name; - str = &info->netbios_name; - lstr->string = talloc_strdup(mem_ctx, str->string); - if (lstr->string == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; - - case FOREST_TRUST_BINARY_DATA: - lftr->type = LSA_FOREST_TRUST_BINARY_DATA; - - blob = data_blob_talloc_named(mem_ctx, - ftr->data.binary.data, - ftr->data.binary.size, - "BINARY_DATA"); - if (blob.length != ftr->data.binary.size) { - return NT_STATUS_NO_MEMORY; - } - - lftr->forest_trust_data.data.data = blob.data; - lftr->forest_trust_data.data.length = blob.length; - - return NT_STATUS_OK; - - case FOREST_TRUST_SCANNER_INFO: - lftr->type = LSA_FOREST_TRUST_SCANNER_INFO; - - linfo = &lftr->forest_trust_data.scanner_info; - info = &ftr->data.scanner_info.info; - - if (info->sid_size != 0) { - linfo->domain_sid = dom_sid_dup(mem_ctx, - &info->sid); - if (linfo->domain_sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - } else { - linfo->domain_sid = NULL; - } - - lstr = &linfo->dns_domain_name; - str = &info->dns_name; - lstr->string = talloc_strdup(mem_ctx, str->string); - if (lstr->string == NULL) { - return NT_STATUS_NO_MEMORY; - } - lstr = &linfo->netbios_domain_name; - str = &info->netbios_name; - lstr->string = talloc_strdup(mem_ctx, str->string); - if (lstr->string == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; - } - - return NT_STATUS_NOT_SUPPORTED; -} - -static NTSTATUS trust_forest_record_lsa_2to1(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustRecord2 *lftr2, - struct lsa_ForestTrustRecord *lftr) -{ - const struct lsa_ForestTrustDomainInfo *s_sdi = NULL; - union ForestTrustData fta = { .unknown = { .size = 0, }, }; - struct ForestTrustDataDomainInfo *d_sdi = NULL; - enum ndr_err_code ndr_err; - DATA_BLOB blob = { .length = 0, }; - - if (lftr2 == NULL) { - return NT_STATUS_INVALID_PARAMETER; - } - - lftr->flags = lftr2->flags; - lftr->time = lftr2->time; - - switch (lftr2->type) { - case LSA_FOREST_TRUST_TOP_LEVEL_NAME: - lftr->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME; - lftr->forest_trust_data.top_level_name = - lftr2->forest_trust_data.top_level_name; - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: - lftr->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX; - lftr->forest_trust_data.top_level_name_ex = - lftr2->forest_trust_data.top_level_name_ex; - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_DOMAIN_INFO: - lftr->type = LSA_FOREST_TRUST_DOMAIN_INFO; - lftr->forest_trust_data.domain_info = - lftr2->forest_trust_data.domain_info; - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_BINARY_DATA: - lftr->type = LSA_FOREST_TRUST_BINARY_DATA; - lftr->forest_trust_data.data = - lftr2->forest_trust_data.data; - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_SCANNER_INFO: - fta.scanner_info.sub_type = FOREST_TRUST_SCANNER_INFO; - s_sdi = &lftr2->forest_trust_data.scanner_info; - d_sdi = &fta.scanner_info.info; - - if (s_sdi->domain_sid != NULL) { - d_sdi->sid = *s_sdi->domain_sid; - } else { - d_sdi->sid = (struct dom_sid) { .sid_rev_num = 0, }; - } - - d_sdi->dns_name.string = s_sdi->dns_domain_name.string; - d_sdi->netbios_name.string = s_sdi->netbios_domain_name.string; - - ndr_err = ndr_push_union_blob(&blob, - mem_ctx, - &fta, - FOREST_TRUST_SCANNER_INFO, - (ndr_push_flags_fn_t)ndr_push_ForestTrustData); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - lftr->type = LSA_FOREST_TRUST_SCANNER_INFO; - lftr->forest_trust_data.data.data = blob.data; - lftr->forest_trust_data.data.length = blob.length; - - return NT_STATUS_OK; - } - - return NT_STATUS_NOT_SUPPORTED; -} - -NTSTATUS trust_forest_info_to_lsa(TALLOC_CTX *mem_ctx, - const struct ForestTrustInfo *fti, - struct lsa_ForestTrustInformation **_lfti) -{ - struct lsa_ForestTrustInformation *lfti; - uint32_t i; - - *_lfti = NULL; - - if (fti->version != 1) { - return NT_STATUS_INVALID_PARAMETER; - } - - lfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation); - if (lfti == NULL) { - return NT_STATUS_NO_MEMORY; - } - - lfti->count = fti->count; - lfti->entries = talloc_zero_array(mem_ctx, - struct lsa_ForestTrustRecord *, - lfti->count); - if (lfti->entries == NULL) { - TALLOC_FREE(lfti); - return NT_STATUS_NO_MEMORY; - } - - for (i = 0; i < fti->count; i++) { - struct ForestTrustInfoRecord *ftr = &fti->records[i].record; - struct lsa_ForestTrustRecord2 lftr2 = { .flags = 0, }; - struct lsa_ForestTrustRecord *lftr = NULL; - NTSTATUS status; - - lftr = talloc_zero(lfti->entries, - struct lsa_ForestTrustRecord); - if (lftr == NULL) { - TALLOC_FREE(lfti); - return NT_STATUS_NO_MEMORY; - } - - status = trust_forest_record_to_lsa(lftr, ftr, &lftr2); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(lfti); - return NT_STATUS_NO_MEMORY; - } - - status = trust_forest_record_lsa_2to1(lftr, &lftr2, lftr); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(lfti); - return NT_STATUS_NO_MEMORY; - } - - lfti->entries[i] = lftr; - } - - *_lfti = lfti; - return NT_STATUS_OK; -} - -static NTSTATUS trust_forest_record_lsa_2to2(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustRecord2 *in, - struct lsa_ForestTrustRecord2 *out) -{ - const struct lsa_ForestTrustBinaryData *binary = NULL; - - if (in == NULL) { - return NT_STATUS_INVALID_PARAMETER; - } - - out->flags = in->flags; - out->time = in->time; - - switch (in->type) { - case LSA_FOREST_TRUST_TOP_LEVEL_NAME: - out->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME; - out->forest_trust_data.top_level_name = - in->forest_trust_data.top_level_name; - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: - out->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX; - out->forest_trust_data.top_level_name_ex = - in->forest_trust_data.top_level_name_ex; - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_DOMAIN_INFO: - out->type = LSA_FOREST_TRUST_DOMAIN_INFO; - out->forest_trust_data.domain_info = - in->forest_trust_data.domain_info; - - return NT_STATUS_OK; - - case LSA_FOREST_TRUST_BINARY_DATA: - binary = &in->forest_trust_data.data; - - return trust_forest_record_lsa_resolve_binary(mem_ctx, - in->flags, - in->time, - binary, - out); - - case LSA_FOREST_TRUST_SCANNER_INFO: - out->type = LSA_FOREST_TRUST_SCANNER_INFO; - out->forest_trust_data.domain_info = - in->forest_trust_data.domain_info; - - return NT_STATUS_OK; - } - - return NT_STATUS_NOT_SUPPORTED; -} - -NTSTATUS trust_forest_info_from_lsa2(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustInformation2 *lfti, - struct ForestTrustInfo **_fti) -{ - struct ForestTrustInfo *fti; - uint32_t i; - - *_fti = NULL; - - fti = talloc_zero(mem_ctx, struct ForestTrustInfo); - if (fti == NULL) { - return NT_STATUS_NO_MEMORY; - } - - fti->version = 1; - fti->count = lfti->count; - fti->records = talloc_zero_array(fti, - struct ForestTrustInfoRecordArmor, - fti->count); - if (fti->records == NULL) { - TALLOC_FREE(fti); - return NT_STATUS_NO_MEMORY; - } - - for (i = 0; i < fti->count; i++) { - const struct lsa_ForestTrustRecord2 *lftr2 = lfti->entries[i]; - struct lsa_ForestTrustRecord2 _lftr2 = { .flags = 0, }; - struct ForestTrustInfoRecord *ftr = &fti->records[i].record; - TALLOC_CTX *frame = talloc_stackframe(); - NTSTATUS status; - - status = trust_forest_record_lsa_2to2(frame, - lftr2, - &_lftr2); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(frame); - TALLOC_FREE(fti); - return status; - } - - status = trust_forest_record_from_lsa(fti->records, - &_lftr2, - ftr); - TALLOC_FREE(frame); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(fti); - return status; - } - } - - *_fti = fti; - return NT_STATUS_OK; -} - -NTSTATUS trust_forest_info_to_lsa2(TALLOC_CTX *mem_ctx, - const struct ForestTrustInfo *fti, - struct lsa_ForestTrustInformation2 **_lfti) -{ - struct lsa_ForestTrustInformation2 *lfti; - uint32_t i; - - *_lfti = NULL; - - if (fti->version != 1) { - return NT_STATUS_INVALID_PARAMETER; - } - - lfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation2); - if (lfti == NULL) { - return NT_STATUS_NO_MEMORY; - } - - lfti->count = fti->count; - lfti->entries = talloc_zero_array(mem_ctx, - struct lsa_ForestTrustRecord2 *, - lfti->count); - if (lfti->entries == NULL) { - TALLOC_FREE(lfti); - return NT_STATUS_NO_MEMORY; - } - - for (i = 0; i < fti->count; i++) { - struct ForestTrustInfoRecord *ftr = &fti->records[i].record; - struct lsa_ForestTrustRecord2 *lftr2 = NULL; - NTSTATUS status; - - lftr2 = talloc_zero(lfti->entries, - struct lsa_ForestTrustRecord2); - if (lftr2 == NULL) { - TALLOC_FREE(lfti); - return NT_STATUS_NO_MEMORY; - } - - status = trust_forest_record_to_lsa(lftr2, ftr, lftr2); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(lfti); - return NT_STATUS_NO_MEMORY; - } - - lfti->entries[i] = lftr2; - } - - *_lfti = lfti; - return NT_STATUS_OK; -} - -NTSTATUS trust_forest_info_lsa_1to2(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustInformation *lfti, - struct lsa_ForestTrustInformation2 **_lfti2) -{ - TALLOC_CTX *frame = talloc_stackframe(); - struct ForestTrustInfo *fti = NULL; - struct lsa_ForestTrustInformation2 *lfti2 = NULL; - NTSTATUS status; - - status = trust_forest_info_from_lsa(frame, lfti, &fti); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(frame); - return status; - } - - status = trust_forest_info_to_lsa2(mem_ctx, - fti, - &lfti2); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(frame); - return status; - } - - *_lfti2 = lfti2; - TALLOC_FREE(frame); - return NT_STATUS_OK; -} - -NTSTATUS trust_forest_info_lsa_2to1(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustInformation2 *lfti2, - struct lsa_ForestTrustInformation **_lfti) -{ - TALLOC_CTX *frame = talloc_stackframe(); - struct ForestTrustInfo *fti = NULL; - struct lsa_ForestTrustInformation *lfti = NULL; - NTSTATUS status; - - status = trust_forest_info_from_lsa2(frame, lfti2, &fti); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(frame); - return status; - } - - status = trust_forest_info_to_lsa(mem_ctx, - fti, - &lfti); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(frame); - return status; - } - - *_lfti = lfti; - TALLOC_FREE(frame); - return NT_STATUS_OK; -} - -NTSTATUS trust_forest_info_lsa_2to2(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustInformation2 *in, - struct lsa_ForestTrustInformation2 **_out) -{ - TALLOC_CTX *frame = talloc_stackframe(); - struct ForestTrustInfo *fti = NULL; - struct lsa_ForestTrustInformation2 *out = NULL; - NTSTATUS status; - - status = trust_forest_info_from_lsa2(frame, in, &fti); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(frame); - return status; - } - - status = trust_forest_info_to_lsa2(mem_ctx, - fti, - &out); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(frame); - return status; - } - - *_out = out; - TALLOC_FREE(frame); - return NT_STATUS_OK; -} - -static int trust_forest_info_tln_match_internal( - const struct lsa_ForestTrustInformation2 *info, - enum lsa_ForestTrustRecordType type, - uint32_t disable_mask, - const char *tln) -{ - uint32_t i; - - for (i = 0; i < info->count; i++) { - struct lsa_ForestTrustRecord2 *e = info->entries[i]; - struct lsa_StringLarge *t = NULL; - int cmp; - - if (e == NULL) { - continue; - } - - if (e->type != type) { - continue; - } - - if (e->flags & disable_mask) { - continue; - } - - switch (type) { - case LSA_FOREST_TRUST_TOP_LEVEL_NAME: - t = &e->forest_trust_data.top_level_name; - break; - case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: - t = &e->forest_trust_data.top_level_name_ex; - break; - default: - break; - } - - if (t == NULL) { - continue; - } - - cmp = dns_cmp(tln, t->string); - switch (cmp) { - case DNS_CMP_MATCH: - case DNS_CMP_FIRST_IS_CHILD: - return i; - } - } - - return -1; -} - -bool trust_forest_info_tln_match( - const struct lsa_ForestTrustInformation2 *info, - const char *tln) -{ - int m; - - m = trust_forest_info_tln_match_internal(info, - LSA_FOREST_TRUST_TOP_LEVEL_NAME, - LSA_TLN_DISABLED_MASK, - tln); - if (m != -1) { - return true; - } - - return false; -} - -bool trust_forest_info_tln_ex_match( - const struct lsa_ForestTrustInformation2 *info, - const char *tln) -{ - int m; - - m = trust_forest_info_tln_match_internal(info, - LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX, - 0, - tln); - if (m != -1) { - return true; - } - - return false; -} - -bool trust_forest_info_match_tln_namespace( - const struct lsa_ForestTrustInformation2 *info, - const char *tln) -{ - bool match; - - match = trust_forest_info_tln_ex_match(info, tln); - if (match) { - return false; - } - - match = trust_forest_info_tln_match(info, tln); - if (!match) { - return false; - } - - return true; -} diff --git a/libcli/lsarpc/util_lsarpc.h b/libcli/lsarpc/util_lsarpc.h index 5fa6fed1e3e..4dc65467436 100644 --- a/libcli/lsarpc/util_lsarpc.h +++ b/libcli/lsarpc/util_lsarpc.h @@ -24,9 +24,6 @@ struct lsa_TrustDomainInfoAuthInfo; struct lsa_TrustDomainInfoBuffer; struct trustAuthInOutBlob; -struct ForestTrustInfo; -struct lsa_ForestTrustInformation; -struct lsa_ForestTrustInformation2; NTSTATUS auth_blob_2_auth_info(TALLOC_CTX *mem_ctx, DATA_BLOB incoming, DATA_BLOB outgoing, @@ -40,36 +37,4 @@ NTSTATUS auth_info_2_auth_blob(TALLOC_CTX *mem_ctx, struct lsa_TrustDomainInfoAuthInfo *auth_info, DATA_BLOB *incoming, DATA_BLOB *outgoing); -NTSTATUS trust_forest_info_from_lsa(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustInformation *lfti, - struct ForestTrustInfo **_fti); -NTSTATUS trust_forest_info_to_lsa(TALLOC_CTX *mem_ctx, - const struct ForestTrustInfo *fti, - struct lsa_ForestTrustInformation **_lfti); -NTSTATUS trust_forest_info_from_lsa2(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustInformation2 *lfti, - struct ForestTrustInfo **_fti); -NTSTATUS trust_forest_info_to_lsa2(TALLOC_CTX *mem_ctx, - const struct ForestTrustInfo *fti, - struct lsa_ForestTrustInformation2 **_lfti); -NTSTATUS trust_forest_info_lsa_1to2(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustInformation *lfti, - struct lsa_ForestTrustInformation2 **_lfti2); -NTSTATUS trust_forest_info_lsa_2to1(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustInformation2 *lfti2, - struct lsa_ForestTrustInformation **_lfti); -NTSTATUS trust_forest_info_lsa_2to2(TALLOC_CTX *mem_ctx, - const struct lsa_ForestTrustInformation2 *in, - struct lsa_ForestTrustInformation2 **_out); - -bool trust_forest_info_tln_match( - const struct lsa_ForestTrustInformation2 *info, - const char *tln); -bool trust_forest_info_tln_ex_match( - const struct lsa_ForestTrustInformation2 *info, - const char *tln); -bool trust_forest_info_match_tln_namespace( - const struct lsa_ForestTrustInformation2 *info, - const char *tln); - #endif /* _LIBCLI_AUTH_UTIL_LSARPC_H_ */ diff --git a/libcli/security/security.h b/libcli/security/security.h index a1c26ed57f4..d42e4c6973b 100644 --- a/libcli/security/security.h +++ b/libcli/security/security.h @@ -117,5 +117,6 @@ struct object_tree { #include "libcli/security/access_check.h" #include "libcli/security/session.h" #include "libcli/security/display_sec.h" +#include "libcli/security/trust_forest_info.h" #endif diff --git a/libcli/security/trust_forest_info.c b/libcli/security/trust_forest_info.c new file mode 100644 index 00000000000..7bb2c4069ac --- /dev/null +++ b/libcli/security/trust_forest_info.c @@ -0,0 +1,971 @@ +/* + Unix SMB/CIFS implementation. + Authentication utility functions + Copyright (C) Stefan Metzmacher 2018,2025 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "replace.h" +#include "libcli/security/security.h" +#include "librpc/gen_ndr/ndr_drsblobs.h" +#include "librpc/gen_ndr/ndr_lsa.h" +#include "lib/util/talloc_stack.h" +#include "lib/util/bytearray.h" +#include "lib/util/dns_cmp.h" + +static NTSTATUS trust_forest_record_from_lsa(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustRecord2 *lftr, + struct ForestTrustInfoRecord *ftr) +{ + struct ForestTrustString *str = NULL; + const struct lsa_StringLarge *lstr = NULL; + const struct lsa_ForestTrustDomainInfo *linfo = NULL; + struct ForestTrustDataDomainInfo *info = NULL; + DATA_BLOB blob = { .length = 0, }; + + if (lftr == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + ftr->flags = lftr->flags; + ftr->timestamp = lftr->time; + + switch (lftr->type) { + case LSA_FOREST_TRUST_TOP_LEVEL_NAME: + ftr->type = FOREST_TRUST_TOP_LEVEL_NAME; + + lstr = &lftr->forest_trust_data.top_level_name; + str = &ftr->data.name; + + str->string = talloc_strdup(mem_ctx, lstr->string); + if (str->string == NULL) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: + ftr->type = FOREST_TRUST_TOP_LEVEL_NAME_EX; + + lstr = &lftr->forest_trust_data.top_level_name_ex; + str = &ftr->data.name; + + str->string = talloc_strdup(mem_ctx, lstr->string); + if (str->string == NULL) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_DOMAIN_INFO: + ftr->type = FOREST_TRUST_DOMAIN_INFO; + + linfo = &lftr->forest_trust_data.domain_info; + info = &ftr->data.info; + + if (linfo->domain_sid == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + info->sid = *linfo->domain_sid; + + lstr = &linfo->dns_domain_name; + str = &info->dns_name; + str->string = talloc_strdup(mem_ctx, lstr->string); + if (str->string == NULL) { + return NT_STATUS_NO_MEMORY; + } + + lstr = &linfo->netbios_domain_name; + str = &info->netbios_name; + str->string = talloc_strdup(mem_ctx, lstr->string); + if (str->string == NULL) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_BINARY_DATA: + ftr->type = FOREST_TRUST_BINARY_DATA; + + blob = data_blob_talloc_named(mem_ctx, + lftr->forest_trust_data.data.data, + lftr->forest_trust_data.data.length, + "BINARY_DATA"); + if (blob.length != lftr->forest_trust_data.data.length) { + return NT_STATUS_NO_MEMORY; + } + ftr->data.binary.data = blob.data; + ftr->data.binary.size = blob.length; + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_SCANNER_INFO: + ftr->type = FOREST_TRUST_SCANNER_INFO; + + linfo = &lftr->forest_trust_data.scanner_info; + info = &ftr->data.scanner_info.info; + + ftr->data.scanner_info.sub_type = FOREST_TRUST_SCANNER_INFO; + + if (linfo->domain_sid != NULL) { + info->sid = *linfo->domain_sid; + } else { + info->sid = (struct dom_sid) { .sid_rev_num = 0, }; + } + + lstr = &linfo->dns_domain_name; + str = &info->dns_name; + str->string = talloc_strdup(mem_ctx, lstr->string); + if (str->string == NULL) { + return NT_STATUS_NO_MEMORY; + } + + lstr = &linfo->netbios_domain_name; + str = &info->netbios_name; + str->string = talloc_strdup(mem_ctx, lstr->string); + if (str->string == NULL) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; + } + + return NT_STATUS_NOT_SUPPORTED; +} + +static NTSTATUS trust_forest_record_lsa_resolve_binary(TALLOC_CTX *mem_ctx, + uint32_t flags, + NTTIME time, + const struct lsa_ForestTrustBinaryData *binary, + struct lsa_ForestTrustRecord2 *lftr2) +{ + enum ForestTrustInfoRecordType sub_type = FOREST_TRUST_BINARY_DATA; + DATA_BLOB blob = { .length = 0, }; + + if (binary == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* + * Note 'binary' may points to + * lftr2->forest_trust_data.data + * + * So we remember the relevant + * information in blob and clear + * the binary pointer in order + * to avoid touching it again. + * + * Because we likely change + * the lftr2->forest_trust_data union + */ + blob.data = binary->data; + blob.length = binary->length; + binary = NULL; + + /* + * We need at least size and subtype + */ + if (blob.length < 5) { + return NT_STATUS_INVALID_PARAMETER; + } + + sub_type = PULL_LE_U8(blob.data, 4); + + /* + * Only levels above LSA_FOREST_TRUST_DOMAIN_INFO + * are handled as binary. + */ + if (sub_type <= FOREST_TRUST_BINARY_DATA) { + return NT_STATUS_INVALID_PARAMETER; + } + + lftr2->flags = flags; + lftr2->time = time; + + /* + * Depending if the sub_type is wellknown the information is upgraded, + * currently only for the LSA_FOREST_TRUST_SCANNER_INFO records. + */ + + if (sub_type == FOREST_TRUST_SCANNER_INFO) { + struct lsa_ForestTrustDomainInfo *d_sdi = NULL; + union ForestTrustData fta = { .unknown = { .size = 0, }, }; + const struct ForestTrustDataDomainInfo *s_sdi = NULL; + enum ndr_err_code ndr_err; + + ndr_err = ndr_pull_union_blob(&blob, + mem_ctx, + &fta, + FOREST_TRUST_SCANNER_INFO, + (ndr_pull_flags_fn_t)ndr_pull_ForestTrustData); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + if (fta.scanner_info.sub_type != FOREST_TRUST_SCANNER_INFO) { + return NT_STATUS_INVALID_PARAMETER; + } + + s_sdi = &fta.scanner_info.info; + d_sdi = &lftr2->forest_trust_data.scanner_info; + + d_sdi->dns_domain_name.string = s_sdi->dns_name.string; + d_sdi->netbios_domain_name.string = s_sdi->netbios_name.string; + + if (s_sdi->sid_size != 0) { + d_sdi->domain_sid = dom_sid_dup(mem_ctx, + &s_sdi->sid); + if (d_sdi->domain_sid == NULL) { + return NT_STATUS_NO_MEMORY; + } + } else { + d_sdi->domain_sid = NULL; + } + + lftr2->type = LSA_FOREST_TRUST_SCANNER_INFO; + + return NT_STATUS_OK; + } + + /* + * In all other cases lftr->type is downgraded to + * LSA_FOREST_TRUST_BINARY_DATA. + */ + + lftr2->type = LSA_FOREST_TRUST_BINARY_DATA; + lftr2->forest_trust_data.data.data = blob.data; + lftr2->forest_trust_data.data.length = blob.length; + + return NT_STATUS_OK; +} + +static NTSTATUS trust_forest_record_lsa_1to2(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustRecord *lftr, + struct lsa_ForestTrustRecord2 *lftr2) +{ + const struct lsa_ForestTrustBinaryData *binary = NULL; + + if (lftr == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + lftr2->flags = lftr->flags; + lftr2->time = lftr->time; + + switch (lftr->type) { + case LSA_FOREST_TRUST_TOP_LEVEL_NAME: + lftr2->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME; + lftr2->forest_trust_data.top_level_name = + lftr->forest_trust_data.top_level_name; + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: + lftr2->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX; + lftr2->forest_trust_data.top_level_name_ex = + lftr->forest_trust_data.top_level_name_ex; + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_DOMAIN_INFO: + lftr2->type = LSA_FOREST_TRUST_DOMAIN_INFO; + lftr2->forest_trust_data.domain_info = + lftr->forest_trust_data.domain_info; + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_BINARY_DATA: + case LSA_FOREST_TRUST_SCANNER_INFO: + /* just to avoid the missing enum switch warning */ + break; + } + + /* + * All levels above LSA_FOREST_TRUST_DOMAIN_INFO are handled as binary. + * + * Depending if the sub_type is wellknown the information is upgraded, + * currently only for the LSA_FOREST_TRUST_SCANNER_INFO records. + * + * In all other cases lftr->type is downgraded to + * LSA_FOREST_TRUST_BINARY_DATA. + */ + + binary = &lftr->forest_trust_data.data; + + return trust_forest_record_lsa_resolve_binary(mem_ctx, + lftr->flags, + lftr->time, + binary, + lftr2); +} + +NTSTATUS trust_forest_info_from_lsa(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustInformation *lfti, + struct ForestTrustInfo **_fti) +{ + struct ForestTrustInfo *fti; + uint32_t i; + + *_fti = NULL; + + fti = talloc_zero(mem_ctx, struct ForestTrustInfo); + if (fti == NULL) { + return NT_STATUS_NO_MEMORY; + } + + fti->version = 1; + fti->count = lfti->count; + fti->records = talloc_zero_array(fti, + struct ForestTrustInfoRecordArmor, + fti->count); + if (fti->records == NULL) { + TALLOC_FREE(fti); + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < fti->count; i++) { + const struct lsa_ForestTrustRecord *lftr = lfti->entries[i]; + struct lsa_ForestTrustRecord2 lftr2 = { .flags = 0, }; + struct ForestTrustInfoRecord *ftr = &fti->records[i].record; + TALLOC_CTX *frame = talloc_stackframe(); + NTSTATUS status; + + status = trust_forest_record_lsa_1to2(frame, + lftr, + &lftr2); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + TALLOC_FREE(fti); + return status; + } + + status = trust_forest_record_from_lsa(fti->records, + &lftr2, + ftr); + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(fti); + return status; + } + } + + *_fti = fti; + return NT_STATUS_OK; +} + +static NTSTATUS trust_forest_record_to_lsa(TALLOC_CTX *mem_ctx, + const struct ForestTrustInfoRecord *ftr, + struct lsa_ForestTrustRecord2 *lftr) +{ + const struct ForestTrustString *str = NULL; + struct lsa_StringLarge *lstr = NULL; + const struct ForestTrustDataDomainInfo *info = NULL; + struct lsa_ForestTrustDomainInfo *linfo = NULL; + DATA_BLOB blob = { .length = 0, }; + + lftr->flags = ftr->flags; + lftr->time = ftr->timestamp; + + switch (ftr->type) { + case FOREST_TRUST_TOP_LEVEL_NAME: + lftr->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME; + + lstr = &lftr->forest_trust_data.top_level_name; + str = &ftr->data.name; + + lstr->string = talloc_strdup(mem_ctx, str->string); + if (lstr->string == NULL) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; + + case FOREST_TRUST_TOP_LEVEL_NAME_EX: + lftr->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX; + + lstr = &lftr->forest_trust_data.top_level_name_ex; + str = &ftr->data.name; + + lstr->string = talloc_strdup(mem_ctx, str->string); + if (lstr->string == NULL) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; + + case FOREST_TRUST_DOMAIN_INFO: + lftr->type = LSA_FOREST_TRUST_DOMAIN_INFO; + + linfo = &lftr->forest_trust_data.domain_info; + info = &ftr->data.info; + + linfo->domain_sid = dom_sid_dup(mem_ctx, &info->sid); + if (linfo->domain_sid == NULL) { + return NT_STATUS_NO_MEMORY; + } + + lstr = &linfo->dns_domain_name; + str = &info->dns_name; + lstr->string = talloc_strdup(mem_ctx, str->string); + if (lstr->string == NULL) { + return NT_STATUS_NO_MEMORY; + } + + lstr = &linfo->netbios_domain_name; + str = &info->netbios_name; + lstr->string = talloc_strdup(mem_ctx, str->string); + if (lstr->string == NULL) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; + + case FOREST_TRUST_BINARY_DATA: + lftr->type = LSA_FOREST_TRUST_BINARY_DATA; + + blob = data_blob_talloc_named(mem_ctx, + ftr->data.binary.data, + ftr->data.binary.size, + "BINARY_DATA"); + if (blob.length != ftr->data.binary.size) { + return NT_STATUS_NO_MEMORY; + } + + lftr->forest_trust_data.data.data = blob.data; + lftr->forest_trust_data.data.length = blob.length; + + return NT_STATUS_OK; + + case FOREST_TRUST_SCANNER_INFO: + lftr->type = LSA_FOREST_TRUST_SCANNER_INFO; + + linfo = &lftr->forest_trust_data.scanner_info; + info = &ftr->data.scanner_info.info; + + if (info->sid_size != 0) { + linfo->domain_sid = dom_sid_dup(mem_ctx, + &info->sid); + if (linfo->domain_sid == NULL) { + return NT_STATUS_NO_MEMORY; + } + } else { + linfo->domain_sid = NULL; + } + + lstr = &linfo->dns_domain_name; + str = &info->dns_name; + lstr->string = talloc_strdup(mem_ctx, str->string); + if (lstr->string == NULL) { + return NT_STATUS_NO_MEMORY; + } + lstr = &linfo->netbios_domain_name; + str = &info->netbios_name; + lstr->string = talloc_strdup(mem_ctx, str->string); + if (lstr->string == NULL) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; + } + + return NT_STATUS_NOT_SUPPORTED; +} + +static NTSTATUS trust_forest_record_lsa_2to1(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustRecord2 *lftr2, + struct lsa_ForestTrustRecord *lftr) +{ + const struct lsa_ForestTrustDomainInfo *s_sdi = NULL; + union ForestTrustData fta = { .unknown = { .size = 0, }, }; + struct ForestTrustDataDomainInfo *d_sdi = NULL; + enum ndr_err_code ndr_err; + DATA_BLOB blob = { .length = 0, }; + + if (lftr2 == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + lftr->flags = lftr2->flags; + lftr->time = lftr2->time; + + switch (lftr2->type) { + case LSA_FOREST_TRUST_TOP_LEVEL_NAME: + lftr->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME; + lftr->forest_trust_data.top_level_name = + lftr2->forest_trust_data.top_level_name; + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: + lftr->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX; + lftr->forest_trust_data.top_level_name_ex = + lftr2->forest_trust_data.top_level_name_ex; + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_DOMAIN_INFO: + lftr->type = LSA_FOREST_TRUST_DOMAIN_INFO; + lftr->forest_trust_data.domain_info = + lftr2->forest_trust_data.domain_info; + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_BINARY_DATA: + lftr->type = LSA_FOREST_TRUST_BINARY_DATA; + lftr->forest_trust_data.data = + lftr2->forest_trust_data.data; + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_SCANNER_INFO: + fta.scanner_info.sub_type = FOREST_TRUST_SCANNER_INFO; + s_sdi = &lftr2->forest_trust_data.scanner_info; + d_sdi = &fta.scanner_info.info; + + if (s_sdi->domain_sid != NULL) { + d_sdi->sid = *s_sdi->domain_sid; + } else { + d_sdi->sid = (struct dom_sid) { .sid_rev_num = 0, }; + } + + d_sdi->dns_name.string = s_sdi->dns_domain_name.string; + d_sdi->netbios_name.string = s_sdi->netbios_domain_name.string; + + ndr_err = ndr_push_union_blob(&blob, + mem_ctx, + &fta, + FOREST_TRUST_SCANNER_INFO, + (ndr_push_flags_fn_t)ndr_push_ForestTrustData); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + lftr->type = LSA_FOREST_TRUST_SCANNER_INFO; + lftr->forest_trust_data.data.data = blob.data; + lftr->forest_trust_data.data.length = blob.length; + + return NT_STATUS_OK; + } + + return NT_STATUS_NOT_SUPPORTED; +} + +NTSTATUS trust_forest_info_to_lsa(TALLOC_CTX *mem_ctx, + const struct ForestTrustInfo *fti, + struct lsa_ForestTrustInformation **_lfti) +{ + struct lsa_ForestTrustInformation *lfti; + uint32_t i; + + *_lfti = NULL; + + if (fti->version != 1) { + return NT_STATUS_INVALID_PARAMETER; + } + + lfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation); + if (lfti == NULL) { + return NT_STATUS_NO_MEMORY; + } + + lfti->count = fti->count; + lfti->entries = talloc_zero_array(mem_ctx, + struct lsa_ForestTrustRecord *, + lfti->count); + if (lfti->entries == NULL) { + TALLOC_FREE(lfti); + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < fti->count; i++) { + struct ForestTrustInfoRecord *ftr = &fti->records[i].record; + struct lsa_ForestTrustRecord2 lftr2 = { .flags = 0, }; + struct lsa_ForestTrustRecord *lftr = NULL; + NTSTATUS status; + + lftr = talloc_zero(lfti->entries, + struct lsa_ForestTrustRecord); + if (lftr == NULL) { + TALLOC_FREE(lfti); + return NT_STATUS_NO_MEMORY; + } + + status = trust_forest_record_to_lsa(lftr, ftr, &lftr2); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(lfti); + return NT_STATUS_NO_MEMORY; + } + + status = trust_forest_record_lsa_2to1(lftr, &lftr2, lftr); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(lfti); + return NT_STATUS_NO_MEMORY; + } + + lfti->entries[i] = lftr; + } + + *_lfti = lfti; + return NT_STATUS_OK; +} + +static NTSTATUS trust_forest_record_lsa_2to2(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustRecord2 *in, + struct lsa_ForestTrustRecord2 *out) +{ + const struct lsa_ForestTrustBinaryData *binary = NULL; + + if (in == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + out->flags = in->flags; + out->time = in->time; + + switch (in->type) { + case LSA_FOREST_TRUST_TOP_LEVEL_NAME: + out->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME; + out->forest_trust_data.top_level_name = + in->forest_trust_data.top_level_name; + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: + out->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX; + out->forest_trust_data.top_level_name_ex = + in->forest_trust_data.top_level_name_ex; + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_DOMAIN_INFO: + out->type = LSA_FOREST_TRUST_DOMAIN_INFO; + out->forest_trust_data.domain_info = + in->forest_trust_data.domain_info; + + return NT_STATUS_OK; + + case LSA_FOREST_TRUST_BINARY_DATA: + binary = &in->forest_trust_data.data; + + return trust_forest_record_lsa_resolve_binary(mem_ctx, + in->flags, + in->time, + binary, + out); + + case LSA_FOREST_TRUST_SCANNER_INFO: + out->type = LSA_FOREST_TRUST_SCANNER_INFO; + out->forest_trust_data.domain_info = + in->forest_trust_data.domain_info; + + return NT_STATUS_OK; + } + + return NT_STATUS_NOT_SUPPORTED; +} + +NTSTATUS trust_forest_info_from_lsa2(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustInformation2 *lfti, + struct ForestTrustInfo **_fti) +{ + struct ForestTrustInfo *fti; + uint32_t i; + + *_fti = NULL; + + fti = talloc_zero(mem_ctx, struct ForestTrustInfo); + if (fti == NULL) { + return NT_STATUS_NO_MEMORY; + } + + fti->version = 1; + fti->count = lfti->count; + fti->records = talloc_zero_array(fti, + struct ForestTrustInfoRecordArmor, + fti->count); + if (fti->records == NULL) { + TALLOC_FREE(fti); + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < fti->count; i++) { + const struct lsa_ForestTrustRecord2 *lftr2 = lfti->entries[i]; + struct lsa_ForestTrustRecord2 _lftr2 = { .flags = 0, }; + struct ForestTrustInfoRecord *ftr = &fti->records[i].record; + TALLOC_CTX *frame = talloc_stackframe(); + NTSTATUS status; + + status = trust_forest_record_lsa_2to2(frame, + lftr2, + &_lftr2); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + TALLOC_FREE(fti); + return status; + } + + status = trust_forest_record_from_lsa(fti->records, + &_lftr2, + ftr); + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(fti); + return status; + } + } + + *_fti = fti; + return NT_STATUS_OK; +} + +NTSTATUS trust_forest_info_to_lsa2(TALLOC_CTX *mem_ctx, + const struct ForestTrustInfo *fti, + struct lsa_ForestTrustInformation2 **_lfti) +{ + struct lsa_ForestTrustInformation2 *lfti; + uint32_t i; + + *_lfti = NULL; + + if (fti->version != 1) { + return NT_STATUS_INVALID_PARAMETER; + } + + lfti = talloc_zero(mem_ctx, struct lsa_ForestTrustInformation2); + if (lfti == NULL) { + return NT_STATUS_NO_MEMORY; + } + + lfti->count = fti->count; + lfti->entries = talloc_zero_array(mem_ctx, + struct lsa_ForestTrustRecord2 *, + lfti->count); + if (lfti->entries == NULL) { + TALLOC_FREE(lfti); + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < fti->count; i++) { + struct ForestTrustInfoRecord *ftr = &fti->records[i].record; + struct lsa_ForestTrustRecord2 *lftr2 = NULL; + NTSTATUS status; + + lftr2 = talloc_zero(lfti->entries, + struct lsa_ForestTrustRecord2); + if (lftr2 == NULL) { + TALLOC_FREE(lfti); + return NT_STATUS_NO_MEMORY; + } + + status = trust_forest_record_to_lsa(lftr2, ftr, lftr2); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(lfti); + return NT_STATUS_NO_MEMORY; + } + + lfti->entries[i] = lftr2; + } + + *_lfti = lfti; + return NT_STATUS_OK; +} + +NTSTATUS trust_forest_info_lsa_1to2(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustInformation *lfti, + struct lsa_ForestTrustInformation2 **_lfti2) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct ForestTrustInfo *fti = NULL; + struct lsa_ForestTrustInformation2 *lfti2 = NULL; + NTSTATUS status; + + status = trust_forest_info_from_lsa(frame, lfti, &fti); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return status; + } + + status = trust_forest_info_to_lsa2(mem_ctx, + fti, + &lfti2); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return status; + } + + *_lfti2 = lfti2; + TALLOC_FREE(frame); + return NT_STATUS_OK; +} + +NTSTATUS trust_forest_info_lsa_2to1(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustInformation2 *lfti2, + struct lsa_ForestTrustInformation **_lfti) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct ForestTrustInfo *fti = NULL; + struct lsa_ForestTrustInformation *lfti = NULL; + NTSTATUS status; + + status = trust_forest_info_from_lsa2(frame, lfti2, &fti); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return status; + } + + status = trust_forest_info_to_lsa(mem_ctx, + fti, + &lfti); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return status; + } + + *_lfti = lfti; + TALLOC_FREE(frame); + return NT_STATUS_OK; +} + +NTSTATUS trust_forest_info_lsa_2to2(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustInformation2 *in, + struct lsa_ForestTrustInformation2 **_out) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct ForestTrustInfo *fti = NULL; + struct lsa_ForestTrustInformation2 *out = NULL; + NTSTATUS status; + + status = trust_forest_info_from_lsa2(frame, in, &fti); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return status; + } + + status = trust_forest_info_to_lsa2(mem_ctx, + fti, + &out); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return status; + } + + *_out = out; + TALLOC_FREE(frame); + return NT_STATUS_OK; +} + +static int trust_forest_info_tln_match_internal( + const struct lsa_ForestTrustInformation2 *info, + enum lsa_ForestTrustRecordType type, + uint32_t disable_mask, + const char *tln) +{ + uint32_t i; + + for (i = 0; i < info->count; i++) { + struct lsa_ForestTrustRecord2 *e = info->entries[i]; + struct lsa_StringLarge *t = NULL; + int cmp; + + if (e == NULL) { + continue; + } + + if (e->type != type) { + continue; + } + + if (e->flags & disable_mask) { + continue; + } + + switch (type) { + case LSA_FOREST_TRUST_TOP_LEVEL_NAME: + t = &e->forest_trust_data.top_level_name; + break; + case LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX: + t = &e->forest_trust_data.top_level_name_ex; + break; + default: + break; + } + + if (t == NULL) { + continue; + } + + cmp = dns_cmp(tln, t->string); + switch (cmp) { + case DNS_CMP_MATCH: + case DNS_CMP_FIRST_IS_CHILD: + return i; + } + } + + return -1; +} + +bool trust_forest_info_tln_match( + const struct lsa_ForestTrustInformation2 *info, + const char *tln) +{ + int m; + + m = trust_forest_info_tln_match_internal(info, + LSA_FOREST_TRUST_TOP_LEVEL_NAME, + LSA_TLN_DISABLED_MASK, + tln); + if (m != -1) { + return true; + } + + return false; +} + +bool trust_forest_info_tln_ex_match( + const struct lsa_ForestTrustInformation2 *info, + const char *tln) +{ + int m; + + m = trust_forest_info_tln_match_internal(info, + LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX, + 0, + tln); + if (m != -1) { + return true; + } + + return false; +} + +bool trust_forest_info_match_tln_namespace( + const struct lsa_ForestTrustInformation2 *info, + const char *tln) +{ + bool match; + + match = trust_forest_info_tln_ex_match(info, tln); + if (match) { + return false; + } + + match = trust_forest_info_tln_match(info, tln); + if (!match) { + return false; + } + + return true; +} diff --git a/libcli/security/trust_forest_info.h b/libcli/security/trust_forest_info.h new file mode 100644 index 00000000000..903cff21f70 --- /dev/null +++ b/libcli/security/trust_forest_info.h @@ -0,0 +1,59 @@ +/* + Unix SMB/CIFS implementation. + Authentication utility functions + Copyright (C) Stefan Metzmacher 2018,2025 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _LIBCLI_SECURITY_TRUST_FOREST_INFO_H_ +#define _LIBCLI_SECURITY_TRUST_FOREST_INFO_H_ + +struct ForestTrustInfo; +struct lsa_ForestTrustInformation; +struct lsa_ForestTrustInformation2; + +NTSTATUS trust_forest_info_from_lsa(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustInformation *lfti, + struct ForestTrustInfo **_fti); +NTSTATUS trust_forest_info_to_lsa(TALLOC_CTX *mem_ctx, + const struct ForestTrustInfo *fti, + struct lsa_ForestTrustInformation **_lfti); +NTSTATUS trust_forest_info_from_lsa2(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustInformation2 *lfti, + struct ForestTrustInfo **_fti); +NTSTATUS trust_forest_info_to_lsa2(TALLOC_CTX *mem_ctx, + const struct ForestTrustInfo *fti, + struct lsa_ForestTrustInformation2 **_lfti); +NTSTATUS trust_forest_info_lsa_1to2(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustInformation *lfti, + struct lsa_ForestTrustInformation2 **_lfti2); +NTSTATUS trust_forest_info_lsa_2to1(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustInformation2 *lfti2, + struct lsa_ForestTrustInformation **_lfti); +NTSTATUS trust_forest_info_lsa_2to2(TALLOC_CTX *mem_ctx, + const struct lsa_ForestTrustInformation2 *in, + struct lsa_ForestTrustInformation2 **_out); + +bool trust_forest_info_tln_match( + const struct lsa_ForestTrustInformation2 *info, + const char *tln); +bool trust_forest_info_tln_ex_match( + const struct lsa_ForestTrustInformation2 *info, + const char *tln); +bool trust_forest_info_match_tln_namespace( + const struct lsa_ForestTrustInformation2 *info, + const char *tln); + +#endif /* _LIBCLI_SECURITY_TRUST_FOREST_INFO_H_ */ diff --git a/libcli/security/wscript_build b/libcli/security/wscript_build index d6b133d1a87..945e5c3c846 100644 --- a/libcli/security/wscript_build +++ b/libcli/security/wscript_build @@ -16,6 +16,18 @@ bld.SAMBA_LIBRARY('samba-security', private_library=True, deps='stable_sort talloc ndr NDR_SECURITY NDR_CONDITIONAL_ACE') +bld.SAMBA_LIBRARY('samba-security-trusts', + source=''' + trust_forest_info.c + ''', + deps=''' + talloc + samba-util + samba-security + ndr-samba + ''', + private_library=True) + pytalloc_util = bld.pyembed_libname('pytalloc-util') pyrpc_util = bld.pyembed_libname('pyrpc_util') bld.SAMBA_PYTHON('pysecurity', diff --git a/source3/wscript_build b/source3/wscript_build index 9e42b046e38..2870f1a704b 100644 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -311,6 +311,7 @@ bld.SAMBA3_SUBSYSTEM('samba3util', LIBTSOCKET util_tsock samba-security + samba-security-trusts NDR_SECURITY samba-util util_tdb diff --git a/source4/dsdb/wscript_build b/source4/dsdb/wscript_build index 1b03dc9f077..c2200f5ce63 100644 --- a/source4/dsdb/wscript_build +++ b/source4/dsdb/wscript_build @@ -16,7 +16,7 @@ bld.SAMBA_LIBRARY('samdb-common', source='common/util.c common/util_trusts.c common/util_groups.c common/util_samr.c common/dsdb_dn.c common/dsdb_access.c common/util_links.c common/rodc_helper.c gmsa/gkdi.c gmsa/util.c', autoproto='common/proto.h', private_library=True, - deps='ldb NDR_DRSBLOBS util_ldb LIBCLI_AUTH samba-hostconfig samba_socket cli-ldap-common flag_mapping UTIL_RUNCMD SAMBA_VERSION samba-security gkdi gmsa' + deps='ldb NDR_DRSBLOBS util_ldb LIBCLI_AUTH samba-hostconfig samba_socket cli-ldap-common flag_mapping UTIL_RUNCMD SAMBA_VERSION samba-security samba-security-trusts gkdi gmsa' )