/* * Copyright (c) 2016 Andreas Schneider * * 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 #include #include #include #include #include #include #include "mscat.h" #include "mscat_private.h" #define ASN1_NULL_DATA "\x05\x00" #define ASN1_NULL_DATA_SIZE 2 #define HASH_SHA1_OBJID "1.3.14.3.2.26" #define HASH_SHA256_OBJID "2.16.840.1.101.3.4.2.1" #define HASH_SHA512_OBJID "2.16.840.1.101.3.4.2.3" #define SPC_INDIRECT_DATA_OBJID "1.3.6.1.4.1.311.2.1.4" #define SPC_PE_IMAGE_DATA_OBJID "1.3.6.1.4.1.311.2.1.15" #define CATALOG_LIST_OBJOID "1.3.6.1.4.1.311.12.1.1" #define CATALOG_LIST_MEMBER_OBJOID "1.3.6.1.4.1.311.12.1.2" #define CATALOG_LIST_MEMBER_V2_OBJOID "1.3.6.1.4.1.311.12.1.3" #define CAT_NAME_VALUE_OBJID "1.3.6.1.4.1.311.12.2.1" #define CAT_MEMBERINFO_OBJID "1.3.6.1.4.1.311.12.2.2" extern const asn1_static_node mscat_asn1_tab[]; struct mscat_ctl { int version; asn1_node asn1_desc; asn1_node tree_ctl; gnutls_datum_t raw_ctl; }; static char *mscat_asn1_get_oid(TALLOC_CTX *mem_ctx, asn1_node root, const char *oid_name) { char oid_str[32] = {0}; int oid_len = sizeof(oid_str); int rc; rc = asn1_read_value(root, oid_name, oid_str, &oid_len); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to read value '%s': %s\n", oid_name, asn1_strerror(rc)); return NULL; } return talloc_strndup(mem_ctx, oid_str, oid_len); } static bool mscat_asn1_oid_equal(const char *o1, const char *o2) { int cmp; cmp = strcmp(o1, o2); if (cmp != 0) { return false; } return true; } static int mscat_asn1_read_value(TALLOC_CTX *mem_ctx, asn1_node root, const char *name, DATA_BLOB *blob) { DATA_BLOB tmp = data_blob_null; unsigned int etype = ASN1_ETYPE_INVALID; int tmp_len = 0; size_t len; int rc; rc = asn1_read_value_type(root, name, NULL, &tmp_len, &etype); if (rc != ASN1_SUCCESS) { return rc; } len = tmp_len; if (etype == ASN1_ETYPE_BIT_STRING) { if (len + 7 < len) { return -1; } len = (len + 7) / 8; } if (len == 0) { *blob = data_blob_null; return 0; } if (len + 1 < len) { return -1; } tmp = data_blob_talloc_zero(mem_ctx, len + 1); if (tmp.data == NULL) { return -1; } rc = asn1_read_value(root, name, tmp.data, &tmp_len); if (rc != ASN1_SUCCESS) { data_blob_free(&tmp); return rc; } len = tmp_len; if (etype == ASN1_ETYPE_BIT_STRING) { if (len + 7 < len) { return -1; } len = (len + 7) / 8; } tmp.length = len; *blob = tmp; return 0; } static int mscat_ctl_cleanup(struct mscat_ctl *ctl) { if (ctl->asn1_desc != NULL) { asn1_delete_structure(&ctl->asn1_desc); } return 0; } struct mscat_ctl *mscat_ctl_init(TALLOC_CTX *mem_ctx) { char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0}; struct mscat_ctl *cat_ctl = NULL; int rc; cat_ctl = talloc_zero(mem_ctx, struct mscat_ctl); if (cat_ctl == NULL) { return NULL; } talloc_set_destructor(cat_ctl, mscat_ctl_cleanup); cat_ctl->asn1_desc = NULL; cat_ctl->tree_ctl = NULL; rc = asn1_array2tree(mscat_asn1_tab, &cat_ctl->asn1_desc, error_string); if (rc != ASN1_SUCCESS) { talloc_free(cat_ctl); DBG_ERR("Failed to create parser tree: %s - %s\n", asn1_strerror(rc), error_string); return NULL; } return cat_ctl; } int mscat_ctl_import(struct mscat_ctl *ctl, struct mscat_pkcs7 *pkcs7) { char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0}; TALLOC_CTX *tmp_ctx = NULL; char *oid; bool ok; int rc; rc = gnutls_pkcs7_get_embedded_data(pkcs7->c, GNUTLS_PKCS7_EDATA_GET_RAW, &ctl->raw_ctl); if (rc != GNUTLS_E_SUCCESS) { DBG_ERR("Failed to get embedded data from pkcs7: %s\n", gnutls_strerror(rc)); return -1; } rc = asn1_create_element(ctl->asn1_desc, "CATALOG.CertTrustList", &ctl->tree_ctl); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to create CertTrustList ASN.1 element - %s\n", asn1_strerror(rc)); return -1; } rc = asn1_der_decoding(&ctl->tree_ctl, ctl->raw_ctl.data, ctl->raw_ctl.size, error_string); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to parse ASN.1 CertTrustList: %s - %s\n", asn1_strerror(rc), error_string); return -1; } tmp_ctx = talloc_new(ctl); if (tmp_ctx == NULL) { return -1; } oid = mscat_asn1_get_oid(tmp_ctx, ctl->tree_ctl, "catalogListId.oid"); if (oid == NULL) { rc = -1; goto done; } ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_OBJOID); if (!ok) { DBG_ERR("Invalid oid (%s), expected CATALOG_LIST_OBJOID\n", oid); rc = -1; goto done; } talloc_free(oid); oid = mscat_asn1_get_oid(tmp_ctx, ctl->tree_ctl, "catalogListMemberId.oid"); if (oid == NULL) { rc = -1; goto done; } ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_MEMBER_V2_OBJOID); if (ok) { ctl->version = 2; } else { ok = mscat_asn1_oid_equal(oid, CATALOG_LIST_MEMBER_OBJOID); if (ok) { ctl->version = 1; } else { DBG_ERR("Invalid oid (%s), expected " "CATALOG_LIST_MEMBER_OBJOID\n", oid); rc = -1; goto done; } } rc = 0; done: talloc_free(tmp_ctx); return rc; } static int ctl_get_member_checksum_string(struct mscat_ctl *ctl, TALLOC_CTX *mem_ctx, unsigned int idx, const char **pchecksum, size_t *pchecksum_size) { TALLOC_CTX *tmp_ctx; DATA_BLOB chksum_ucs2 = data_blob_null; size_t converted_size = 0; char *checksum = NULL; char *element = NULL; int rc = -1; bool ok; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return -1; } element = talloc_asprintf(tmp_ctx, "members.?%u.checksum", idx); if (element == NULL) { goto done; } rc = mscat_asn1_read_value(tmp_ctx, ctl->tree_ctl, element, &chksum_ucs2); talloc_free(element); if (rc != 0) { goto done; } ok = convert_string_talloc(mem_ctx, CH_UTF16LE, CH_UNIX, chksum_ucs2.data, chksum_ucs2.length, &checksum, &converted_size); if (!ok) { rc = -1; goto done; } *pchecksum_size = strlen(checksum) + 1; *pchecksum = talloc_move(mem_ctx, &checksum); rc = 0; done: talloc_free(tmp_ctx); return rc; } static int ctl_get_member_checksum_blob(struct mscat_ctl *ctl, TALLOC_CTX *mem_ctx, unsigned int idx, uint8_t **pchecksum, size_t *pchecksum_size) { TALLOC_CTX *tmp_ctx; DATA_BLOB chksum = data_blob_null; char *element = NULL; int rc = -1; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return -1; } element = talloc_asprintf(tmp_ctx, "members.?%u.checksum", idx); if (element == NULL) { goto done; } rc = mscat_asn1_read_value(tmp_ctx, ctl->tree_ctl, element, &chksum); talloc_free(element); if (rc != 0) { goto done; } *pchecksum = talloc_move(mem_ctx, &chksum.data); *pchecksum_size = chksum.length; rc = 0; done: talloc_free(tmp_ctx); return rc; } static int ctl_parse_name_value(struct mscat_ctl *ctl, TALLOC_CTX *mem_ctx, DATA_BLOB *content, char **pname, uint32_t *pflags, char **pvalue) { char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0}; asn1_node name_value = NULL; TALLOC_CTX *tmp_ctx; DATA_BLOB name_blob = data_blob_null; DATA_BLOB flags_blob = data_blob_null; DATA_BLOB value_blob = data_blob_null; size_t converted_size = 0; bool ok; int rc; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return -1; } rc = asn1_create_element(ctl->asn1_desc, "CATALOG.CatalogNameValue", &name_value); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to create element for " "CATALOG.CatalogNameValue: %s\n", asn1_strerror(rc)); goto done; } rc = asn1_der_decoding(&name_value, content->data, content->length, error_string); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to decode CATALOG.CatalogNameValue: %s - %s\n", asn1_strerror(rc), error_string); goto done; } rc = mscat_asn1_read_value(mem_ctx, name_value, "name", &name_blob); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to read 'name': %s\n", asn1_strerror(rc)); goto done; } rc = mscat_asn1_read_value(mem_ctx, name_value, "flags", &flags_blob); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to read 'flags': %s\n", asn1_strerror(rc)); goto done; } rc = mscat_asn1_read_value(mem_ctx, name_value, "value", &value_blob); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to read 'value': %s\n", asn1_strerror(rc)); goto done; } ok = convert_string_talloc(mem_ctx, CH_UTF16BE, CH_UNIX, name_blob.data, name_blob.length, pname, &converted_size); if (!ok) { rc = ASN1_MEM_ERROR; goto done; } *pflags = RIVAL(flags_blob.data, 0); ok = convert_string_talloc(mem_ctx, CH_UTF16LE, CH_UNIX, value_blob.data, value_blob.length, pvalue, &converted_size); if (!ok) { rc = ASN1_MEM_ERROR; goto done; } rc = 0; done: talloc_free(tmp_ctx); return rc; } static int ctl_parse_member_info(struct mscat_ctl *ctl, TALLOC_CTX *mem_ctx, DATA_BLOB *content, char **pname, uint32_t *pid) { char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0}; asn1_node member_info = NULL; TALLOC_CTX *tmp_ctx; DATA_BLOB name_blob = data_blob_null; DATA_BLOB id_blob = data_blob_null; size_t converted_size = 0; bool ok; int rc; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return -1; } rc = asn1_create_element(ctl->asn1_desc, "CATALOG.CatalogMemberInfo", &member_info); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to create element for " "CATALOG.CatalogMemberInfo: %s\n", asn1_strerror(rc)); goto done; } rc = asn1_der_decoding(&member_info, content->data, content->length, error_string); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to decode CATALOG.CatalogMemberInfo: %s - %s\n", asn1_strerror(rc), error_string); goto done; } rc = mscat_asn1_read_value(mem_ctx, member_info, "name", &name_blob); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to read 'name': %s\n", asn1_strerror(rc)); goto done; } rc = mscat_asn1_read_value(mem_ctx, member_info, "id", &id_blob); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to read 'id': %s\n", asn1_strerror(rc)); goto done; } ok = convert_string_talloc(mem_ctx, CH_UTF16BE, CH_UNIX, name_blob.data, name_blob.length, pname, &converted_size); if (!ok) { rc = ASN1_MEM_ERROR; goto done; } *pid = RSVAL(id_blob.data, 0); rc = 0; done: talloc_free(tmp_ctx); return rc; } static int ctl_spc_pe_image_data(struct mscat_ctl *ctl, TALLOC_CTX *mem_ctx, DATA_BLOB *content, char **pfile) { char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0}; asn1_node spc_pe_image_data = NULL; DATA_BLOB flags_blob = data_blob_null; DATA_BLOB choice_blob = data_blob_null; char *file = NULL; TALLOC_CTX *tmp_ctx; int cmp; int rc; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return -1; } rc = asn1_create_element(ctl->asn1_desc, "CATALOG.SpcPEImageData", &spc_pe_image_data); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to create element for " "CATALOG.SpcPEImageData: %s\n", asn1_strerror(rc)); goto done; } rc = asn1_der_decoding(&spc_pe_image_data, content->data, content->length, error_string); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to decode CATALOG.SpcPEImageData: %s - %s\n", asn1_strerror(rc), error_string); goto done; } rc = mscat_asn1_read_value(tmp_ctx, spc_pe_image_data, "flags", &flags_blob); if (rc == ASN1_SUCCESS) { uint32_t flags = RIVAL(flags_blob.data, 0); DBG_ERR(">>> SPC_PE_IMAGE_DATA FLAGS=0x%08x\n", flags); } else { DBG_ERR("Failed to parse 'flags' in CATALOG.SpcPEImageData - %s\n", asn1_strerror(rc)); goto done; } rc = mscat_asn1_read_value(tmp_ctx, spc_pe_image_data, "link", &choice_blob); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to parse 'link' in CATALOG.SpcPEImageData - %s\n", asn1_strerror(rc)); goto done; } cmp = strncmp((char *)choice_blob.data, "url", choice_blob.length); if (cmp == 0) { /* Never seen in a printer catalog file yet */ DBG_INFO("Please report a Samba bug and attach the catalog " "file\n"); } cmp = strncmp((char *)choice_blob.data, "moniker", choice_blob.length); if (cmp == 0) { /* Never seen in a printer catalog file yet */ DBG_INFO("Please report a Samba bug and attach the catalog " "file\n"); } cmp = strncmp((char *)choice_blob.data, "file", choice_blob.length); if (cmp == 0) { DATA_BLOB file_blob; char *link; rc = mscat_asn1_read_value(tmp_ctx, spc_pe_image_data, "link.file", &choice_blob); if (rc != ASN1_SUCCESS) { goto done; } link = talloc_asprintf(tmp_ctx, "link.file.%s", (char *)choice_blob.data); if (link == NULL) { rc = -1; goto done; } rc = mscat_asn1_read_value(tmp_ctx, spc_pe_image_data, link, &file_blob); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to read '%s' - %s\n", link, asn1_strerror(rc)); rc = -1; goto done; } cmp = strncmp((char *)choice_blob.data, "unicode", choice_blob.length); if (cmp == 0) { size_t converted_size = 0; bool ok; ok = convert_string_talloc(tmp_ctx, CH_UTF16BE, CH_UNIX, file_blob.data, file_blob.length, &file, &converted_size); if (!ok) { rc = -1; goto done; } } cmp = strncmp((char *)choice_blob.data, "ascii", choice_blob.length); if (cmp == 0) { file = talloc_strndup(tmp_ctx, (char *)file_blob.data, file_blob.length); if (file == NULL) { rc = -1; goto done; } } } if (file != NULL) { *pfile = talloc_move(mem_ctx, &file); } rc = 0; done: talloc_free(tmp_ctx); return rc; } static int ctl_spc_indirect_data(struct mscat_ctl *ctl, TALLOC_CTX *mem_ctx, DATA_BLOB *content, enum mscat_mac_algorithm *pmac_algorithm, uint8_t **pdigest, size_t *pdigest_size) { char error_string[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = {0}; asn1_node spc_indirect_data = NULL; TALLOC_CTX *tmp_ctx; enum mscat_mac_algorithm mac_algorithm = MSCAT_MAC_UNKNOWN; const char *oid = NULL; DATA_BLOB data_value_blob = data_blob_null; DATA_BLOB digest_parameters_blob = data_blob_null; DATA_BLOB digest_blob = data_blob_null; bool ok; int rc; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return -1; } rc = asn1_create_element(ctl->asn1_desc, "CATALOG.SpcIndirectData", &spc_indirect_data); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to create element for " "CATALOG.SpcIndirectData: %s\n", asn1_strerror(rc)); goto done; } rc = asn1_der_decoding(&spc_indirect_data, content->data, content->length, error_string); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to decode CATALOG.SpcIndirectData: %s - %s\n", asn1_strerror(rc), error_string); goto done; } oid = mscat_asn1_get_oid(tmp_ctx, spc_indirect_data, "data.type"); if (oid == NULL) { goto done; } rc = mscat_asn1_read_value(tmp_ctx, spc_indirect_data, "data.value", &data_value_blob); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to find data.value in SpcIndirectData: %s\n", asn1_strerror(rc)); goto done; } ok = mscat_asn1_oid_equal(oid, SPC_PE_IMAGE_DATA_OBJID); if (ok) { char *file = NULL; rc = ctl_spc_pe_image_data(ctl, tmp_ctx, &data_value_blob, &file); if (rc != 0) { goto done; } /* Just returns <<>> as file */ DBG_NOTICE(">>> LINK: %s\n", file); } oid = mscat_asn1_get_oid(tmp_ctx, spc_indirect_data, "messageDigest.digestAlgorithm.algorithm"); if (oid == NULL) { goto done; } rc = mscat_asn1_read_value(tmp_ctx, spc_indirect_data, "messageDigest.digestAlgorithm.parameters", &digest_parameters_blob); if (rc == ASN1_SUCCESS) { /* Make sure we don't have garbage */ int cmp; if (digest_parameters_blob.length != ASN1_NULL_DATA_SIZE) { rc = -1; goto done; } cmp = memcmp(digest_parameters_blob.data, ASN1_NULL_DATA, digest_parameters_blob.length); if (cmp != 0) { rc = -1; goto done; } } else if (rc != ASN1_ELEMENT_NOT_FOUND) { DBG_ERR("Failed to read 'messageDigest.digestAlgorithm.parameters': %s\n", asn1_strerror(rc)); goto done; } ok = mscat_asn1_oid_equal(oid, HASH_SHA1_OBJID); if (ok) { mac_algorithm = MSCAT_MAC_SHA1; } ok = mscat_asn1_oid_equal(oid, HASH_SHA256_OBJID); if (ok) { mac_algorithm = MSCAT_MAC_SHA256; } if (mac_algorithm != MSCAT_MAC_UNKNOWN && mac_algorithm != MSCAT_MAC_NULL) { rc = mscat_asn1_read_value(tmp_ctx, spc_indirect_data, "messageDigest.digest", &digest_blob); if (rc != ASN1_SUCCESS) { DBG_ERR("Failed to find messageDigest.digest in " "SpcIndirectData: %s\n", asn1_strerror(rc)); goto done; } } *pmac_algorithm = mac_algorithm; *pdigest = talloc_move(mem_ctx, &digest_blob.data); *pdigest_size = digest_blob.length; rc = 0; done: talloc_free(tmp_ctx); return rc; } static int ctl_get_member_attributes(struct mscat_ctl *ctl, TALLOC_CTX *mem_ctx, unsigned int idx, struct mscat_ctl_member *m) { TALLOC_CTX *tmp_ctx; char *el1 = NULL; int count = 0; int i; int rc = -1; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return -1; } el1 = talloc_asprintf(tmp_ctx, "members.?%u.attributes", idx); if (el1 == NULL) { goto done; } rc = asn1_number_of_elements(ctl->tree_ctl, el1, &count); if (rc != ASN1_SUCCESS) { goto done; } for (i = 0; i < count; i++) { int content_start = 0; int content_end = 0; size_t content_len; DATA_BLOB content; char *el2; char *oid; bool ok; el2 = talloc_asprintf(tmp_ctx, "%s.?%d.contentType", el1, i + 1); if (el2 == NULL) { rc = -1; goto done; } oid = mscat_asn1_get_oid(tmp_ctx, ctl->tree_ctl, el2); talloc_free(el2); if (oid == NULL) { rc = -1; goto done; } /* FIXME Looks like this is always 1 */ el2 = talloc_asprintf(tmp_ctx, "%s.?%d.content.?1", el1, i + 1); if (el2 == NULL) { rc = -1; goto done; } DBG_DEBUG("Decode element (startEnd) %s\n", el2); rc = asn1_der_decoding_startEnd(ctl->tree_ctl, ctl->raw_ctl.data, ctl->raw_ctl.size, el2, &content_start, &content_end); if (rc != ASN1_SUCCESS) { goto done; } if (content_start < content_end) { goto done; } content_len = content_end - content_start + 1; DBG_DEBUG("Content data_blob length: %zu\n", content_len); content = data_blob_talloc_zero(tmp_ctx, content_len); if (content.data == NULL) { rc = -1; goto done; } memcpy(content.data, &ctl->raw_ctl.data[content_start], content_len); ok = mscat_asn1_oid_equal(oid, CAT_NAME_VALUE_OBJID); if (ok) { char *name; uint32_t flags; char *value; int cmp; rc = ctl_parse_name_value(ctl, tmp_ctx, &content, &name, &flags, &value); if (rc != 0) { goto done; } DBG_DEBUG("Parsed NameValue: name=%s, flags=%u, value=%s\n", name, flags, value); cmp = strcmp(name, "File"); if (cmp == 0) { m->file.name = talloc_move(m, &value); m->file.flags = flags; continue; } cmp = strcmp(name, "OSAttr"); if (cmp == 0) { m->osattr.value = talloc_move(m, &value); m->osattr.flags = flags; continue; } } ok = mscat_asn1_oid_equal(oid, CAT_MEMBERINFO_OBJID); if (ok) { char *name = NULL; uint32_t id = 0; rc = ctl_parse_member_info(ctl, tmp_ctx, &content, &name, &id); if (rc != 0) { goto done; } m->info.guid = talloc_move(m, &name); m->info.id = id; continue; } ok = mscat_asn1_oid_equal(oid, SPC_INDIRECT_DATA_OBJID); if (ok) { rc = ctl_spc_indirect_data(ctl, m, &content, &m->mac.type, &m->mac.digest, &m->mac.digest_size); if (rc != 0) { goto done; } continue; } } rc = 0; done: talloc_free(tmp_ctx); return rc; } int mscat_ctl_get_member(struct mscat_ctl *ctl, TALLOC_CTX *mem_ctx, unsigned int idx, struct mscat_ctl_member **pmember) { TALLOC_CTX *tmp_ctx; struct mscat_ctl_member *m = NULL; int rc = -1; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return -1; } m = talloc_zero(tmp_ctx, struct mscat_ctl_member); if (m == NULL) { rc = -1; goto done; } if (ctl->version == 1) { m->checksum.type = MSCAT_CHECKSUM_STRING; rc = ctl_get_member_checksum_string(ctl, m, idx, &m->checksum.string, &m->checksum.size); } else if (ctl->version == 2) { m->checksum.type = MSCAT_CHECKSUM_BLOB; rc = ctl_get_member_checksum_blob(ctl, m, idx, &m->checksum.blob, &m->checksum.size); } if (rc != 0) { goto done; } rc = ctl_get_member_attributes(ctl, mem_ctx, idx, m); if (rc != 0) { goto done; } *pmember = talloc_move(mem_ctx, &m); rc = 0; done: talloc_free(tmp_ctx); return rc; } int mscat_ctl_get_member_count(struct mscat_ctl *ctl) { int count = 0; int rc; rc = asn1_number_of_elements(ctl->tree_ctl, "members", &count); if (rc != ASN1_SUCCESS) { return -1; } return count; } int mscat_ctl_get_attribute(struct mscat_ctl *ctl, TALLOC_CTX *mem_ctx, unsigned int idx, struct mscat_ctl_attribute **pattribute) { TALLOC_CTX *tmp_ctx; const char *el1 = NULL; const char *el2 = NULL; const char *oid = NULL; char *name = NULL; uint32_t flags = 0; char *value = NULL; struct mscat_ctl_attribute *a = NULL; DATA_BLOB encapsulated_data_blob = data_blob_null; int rc; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return -1; } a = talloc_zero(tmp_ctx, struct mscat_ctl_attribute); if (a == NULL) { rc = -1; goto done; } el1 = talloc_asprintf(tmp_ctx, "attributes.?%u.dataId", idx); if (el1 == NULL) { rc = -1; goto done; } oid = mscat_asn1_get_oid(tmp_ctx, ctl->tree_ctl, el1); if (oid == NULL) { rc = -1; goto done; } el2 = talloc_asprintf(tmp_ctx, "attributes.?%u.encapsulated_data", idx); if (el2 == NULL) { rc = -1; goto done; } rc = mscat_asn1_read_value(tmp_ctx, ctl->tree_ctl, el2, &encapsulated_data_blob); if (rc != ASN1_SUCCESS) { goto done; } rc = ctl_parse_name_value(ctl, tmp_ctx, &encapsulated_data_blob, &name, &flags, &value); if (rc != 0) { goto done; } a->name = talloc_move(a, &name); a->flags = flags; a->value = talloc_move(a, &value); *pattribute = talloc_move(mem_ctx, &a); rc = 0; done: talloc_free(tmp_ctx); return rc; } int mscat_ctl_get_attribute_count(struct mscat_ctl *ctl) { int count = 0; int rc; rc = asn1_number_of_elements(ctl->tree_ctl, "attributes", &count); if (rc != ASN1_SUCCESS) { return -1; } return count; }