summaryrefslogtreecommitdiff
path: root/Add-digest-list-plugin.patch
diff options
context:
space:
mode:
Diffstat (limited to 'Add-digest-list-plugin.patch')
-rw-r--r--Add-digest-list-plugin.patch700
1 files changed, 700 insertions, 0 deletions
diff --git a/Add-digest-list-plugin.patch b/Add-digest-list-plugin.patch
new file mode 100644
index 0000000..14c89b5
--- /dev/null
+++ b/Add-digest-list-plugin.patch
@@ -0,0 +1,700 @@
+From 3b2fb7d5a40d25c3295e02eb3695a45189342369 Mon Sep 17 00:00:00 2001
+From: zhoushuiqing <zhoushuiqing2@huawei.com>
+Date: Fri, 16 Jun 2023 11:21:37 +0800
+Subject: [PATCH] Add-digest-list-plugin
+
+Signed-off-by: Huaxin Lu <luhuaxin1@huawei.com>
+---
+ plugins/digest_list.c | 680 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 680 insertions(+)
+ create mode 100644 plugins/digest_list.c
+
+diff --git a/plugins/digest_list.c b/plugins/digest_list.c
+new file mode 100644
+index 0000000..715b8d6
+--- /dev/null
++++ b/plugins/digest_list.c
+@@ -0,0 +1,680 @@
++/*
++ * Copyright (C) 2020-2021 Huawei Technologies Duesseldorf GmbH
++ *
++ * Author: Roberto Sassu <roberto.sassu@huawei.com>
++ *
++ * 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, version 2 of the
++ * License.
++ *
++ * File: digest_list.c
++ * Plugin to load digest lists in the Linux kernel.
++ */
++
++#include "system.h"
++#include "errno.h"
++
++#include <fcntl.h>
++#include <rpm/rpmlog.h>
++#include <rpm/rpmts.h>
++#include <rpm/header.h>
++#include <rpm/rpmpgp.h>
++#include "rpmio/rpmpgp_internal.h"
++#include <rpm/rpmfileutil.h>
++#include "lib/rpmplugin.h"
++#include <netinet/in.h>
++#include <sys/stat.h>
++#include <openssl/sha.h>
++#include <sys/xattr.h>
++#include <sys/capability.h>
++#include <linux/xattr.h>
++#include <asm/byteorder.h>
++#include <sys/wait.h>
++
++#include "debug.h"
++
++#define IMA_DIR "/sys/kernel/security/ima"
++#define DIGEST_LIST_DATA_PATH IMA_DIR "/digest_list_data"
++#define DIGEST_LIST_DATA_DEL_PATH IMA_DIR "/digest_list_data_del"
++#define DIGEST_LIST_COUNT IMA_DIR "/digests_count"
++#define DIGEST_LIST_DEFAULT_PATH "/etc/ima/digest_lists"
++#define RPM_PARSER "/usr/libexec/rpm_parser"
++
++enum hash_algo {
++ HASH_ALGO_MD4,
++ HASH_ALGO_MD5,
++ HASH_ALGO_SHA1,
++ HASH_ALGO_RIPE_MD_160,
++ HASH_ALGO_SHA256,
++ HASH_ALGO_SHA384,
++ HASH_ALGO_SHA512,
++ HASH_ALGO_SHA224,
++ HASH_ALGO_RIPE_MD_128,
++ HASH_ALGO_RIPE_MD_256,
++ HASH_ALGO_RIPE_MD_320,
++ HASH_ALGO_WP_256,
++ HASH_ALGO_WP_384,
++ HASH_ALGO_WP_512,
++ HASH_ALGO_TGR_128,
++ HASH_ALGO_TGR_160,
++ HASH_ALGO_TGR_192,
++ HASH_ALGO_SM3_256,
++ HASH_ALGO__LAST
++};
++
++#define PGPHASHALGO__LAST PGPHASHALGO_SHA224 + 1
++enum hash_algo pgp_algo_mapping[PGPHASHALGO__LAST] = {
++ [PGPHASHALGO_MD5] = HASH_ALGO_MD5,
++ [PGPHASHALGO_SHA1] = HASH_ALGO_SHA1,
++ [PGPHASHALGO_SHA224] = HASH_ALGO_SHA224,
++ [PGPHASHALGO_SHA256] = HASH_ALGO_SHA256,
++ [PGPHASHALGO_SHA384] = HASH_ALGO_SHA384,
++ [PGPHASHALGO_SHA512] = HASH_ALGO_SHA512,
++};
++
++/* from integrity.h */
++enum evm_ima_xattr_type {
++ IMA_XATTR_DIGEST = 0x01,
++ EVM_XATTR_HMAC,
++ EVM_IMA_XATTR_DIGSIG,
++ IMA_XATTR_DIGEST_NG,
++ EVM_XATTR_PORTABLE_DIGSIG,
++ EVM_IMA_XATTR_DIGEST_LIST,
++ IMA_XATTR_LAST
++};
++
++struct evm_ima_xattr_data {
++ uint8_t type;
++ uint8_t digest[SHA512_DIGEST_LENGTH + 1];
++} __attribute__((packed));
++
++struct signature_v2_hdr {
++ uint8_t type; /* xattr type */
++ uint8_t version; /* signature format version */
++ uint8_t hash_algo; /* Digest algorithm [enum hash_algo] */
++ __be32 keyid; /* IMA key identifier - not X509/PGP specific */
++ __be16 sig_size; /* signature size */
++ uint8_t sig[0]; /* signature payload */
++} __attribute__((packed));
++
++static int digest_list_count_is_zero(void)
++{
++ int fd = 0, ret = 0;
++ char first = 0;
++
++ fd = open(DIGEST_LIST_COUNT, O_RDONLY);
++ if (fd < 0) {
++ rpmlog(RPMLOG_ERR, "digest_list: could not open IMA interface "
++ "'%s': %s\n", DIGEST_LIST_COUNT, strerror(errno));
++ return -EACCES;
++ }
++
++ ret = read(fd, &first, 1);
++ if (ret <= 0) {
++ rpmlog(RPMLOG_ERR, "digest_list: could not read from IMA "
++ "interface '%s': %s\n", DIGEST_LIST_COUNT,
++ strerror(errno));
++ close(fd);
++ return -EACCES;
++ }
++
++ close(fd);
++ return (first == '0');
++}
++
++static int upload_digest_list(char *path, int type, int digest_list_signed)
++{
++ int ret = 0, fd = 0;
++ pid_t pid = 0;
++ size_t size = 0;
++ struct stat st;
++ const char *ima_path = NULL;
++
++ ima_path = (type == TR_REMOVED) ? DIGEST_LIST_DATA_DEL_PATH :
++ DIGEST_LIST_DATA_PATH;
++ if (stat(ima_path, &st) == -1) {
++ rpmlog(RPMLOG_DEBUG, "digest_list: '%s' interface "
++ "not exist\n", ima_path);
++ return RPMRC_OK;
++ }
++
++ /* First determine if kernel interface can accept new digest lists */
++ if (digest_list_count_is_zero()) {
++ rpmlog(RPMLOG_DEBUG, "digest_list: the count is 0, not "
++ "upload '%s' to IMA interface '%s'\n", path, ima_path);
++ return RPMRC_OK;
++ }
++
++ /* If the digest list is not signed, execute the RPM parser */
++ if (!digest_list_signed) {
++ if (stat(RPM_PARSER, &st) == -1) {
++ rpmlog(RPMLOG_DEBUG, "digest_list: %s not found, "
++ "not uploading digest list\n", RPM_PARSER);
++ return RPMRC_OK;
++ }
++
++ if ((pid = fork()) == 0) {
++ execlp(RPM_PARSER, RPM_PARSER, (type == TR_ADDED) ?
++ "add" : "del", path, NULL);
++ _exit(EXIT_FAILURE);
++ }
++
++ waitpid(pid, &ret, 0);
++ if (ret != 0)
++ rpmlog(RPMLOG_ERR, "digest_list: %s returned %d\n",
++ RPM_PARSER, ret);
++ return RPMRC_OK;
++ }
++
++ /* If the digest list is signed, write path to the IMA interface */
++ fd = open(ima_path, O_WRONLY);
++ if (fd < 0) {
++ rpmlog(RPMLOG_ERR, "digest_list: rcould not open IMA interface "
++ "'%s': %s\n", ima_path, strerror(errno));
++ return -EACCES;
++ }
++
++ /* Write the path of the digest list to securityfs */
++ size = write(fd, path, strlen(path));
++ if (size != strlen(path)) {
++ rpmlog(RPMLOG_ERR, "digest_list: could not write '%s' to IMA "
++ "interface '%s': %s\n", path, ima_path, strerror(errno));
++ ret = -EIO;
++ goto out;
++ }
++
++ rpmlog(RPMLOG_DEBUG, "digest_list: written '%s' to '%s'\n", path,
++ ima_path);
++out:
++ close(fd);
++ return ret;
++}
++
++static int write_rpm_digest_list(rpmte te, char *path)
++{
++ FD_t fd;
++ int ret = 0;
++ ssize_t written = 0;
++ Header rpm = rpmteHeader(te);
++ rpmtd immutable = rpmtdNew();
++
++ headerGet(rpm, RPMTAG_HEADERIMMUTABLE, immutable, 0);
++
++ fd = Fopen(path, "w.ufdio");
++ if (fd == NULL || Ferror(fd)) {
++ ret = -EACCES;
++ goto out;
++ }
++
++ written = Fwrite(rpm_header_magic, sizeof(uint8_t),
++ sizeof(rpm_header_magic), fd);
++ if (written != sizeof(rpm_header_magic)) {
++ ret = -EIO;
++ goto out;
++ }
++
++ written = Fwrite(immutable->data, sizeof(uint8_t),
++ immutable->count, fd);
++ if (written != immutable->count || Ferror(fd))
++ ret = -EIO;
++out:
++ Fclose(fd);
++ rpmtdFree(immutable);
++ return ret;
++}
++
++static int write_rpm_digest_list_ima_xattr(rpmte te, char *path)
++{
++ FD_t fd;
++ ssize_t written = 0;
++ int ret = 0, sig_size = 0, sig_size_rounded = 0;
++ uint8_t sig[2048] = { 0 };
++ pgpDigParams sigp = NULL;
++ struct signature_v2_hdr *sig_hdr = (struct signature_v2_hdr *)sig;
++ Header rpm = rpmteHeader(te);
++ rpmtd signature = rpmtdNew();
++
++ headerGet(rpm, RPMTAG_RSAHEADER, signature, 0);
++ ret = pgpPrtParams(signature->data, signature->count,
++ PGPTAG_SIGNATURE, &sigp);
++ if (ret) {
++ ret = -ENOENT;
++ goto out;
++ }
++
++ fd = Fopen(path, "a.ufdio");
++ if (fd == NULL || Ferror(fd)) {
++ ret = -EACCES;
++ goto out;
++ }
++
++ written = Fwrite(sigp->hash, sizeof(uint8_t),
++ sigp->hashlen, fd);
++ if (written != sigp->hashlen || Ferror(fd)) {
++ ret = -EIO;
++ goto out;
++ }
++
++ if (sigp->version == 4) {
++ /* V4 trailer is six octets long (rfc4880) */
++ uint8_t trailer[6];
++ uint32_t nb = sigp->hashlen;
++ nb = htonl(nb);
++ trailer[0] = sigp->version;
++ trailer[1] = 0xff;
++ memcpy(trailer+2, &nb, 4);
++
++ written = Fwrite(trailer, sizeof(uint8_t), sizeof(trailer), fd);
++ if (written != sizeof(trailer) || Ferror(fd)) {
++ ret = -EIO;
++ goto out;
++ }
++ }
++
++ Fclose(fd);
++
++ sig_hdr->type = EVM_IMA_XATTR_DIGSIG;
++ sig_hdr->version = 2;
++ sig_hdr->hash_algo = pgp_algo_mapping[sigp->hash_algo];
++ memcpy((void *)&sig_hdr->keyid, sigp->signid + sizeof(uint32_t),
++ sizeof(uint32_t));
++
++ sig_size = (pgpMpiBits(sigp->data) + 7) >> 3;
++ if (sizeof(sig_hdr) + sig_size > sizeof(sig)) {
++ rpmlog(RPMLOG_ERR,
++ "digest_list: signature in %s too big\n", path);
++ ret = -E2BIG;
++ goto out;
++ }
++
++ sig_size_rounded = ((sig_size + 7) >> 3) * 8;
++ sig_hdr->sig_size = __cpu_to_be16(sig_size_rounded);
++
++ memcpy(sig_hdr->sig + sig_size_rounded - sig_size,
++ (uint8_t *)sigp->data + 2, sig_size);
++
++ ret = lsetxattr(path, XATTR_NAME_IMA,
++ sig, sizeof(*sig_hdr) + sig_size_rounded, 0);
++ if (ret < 0)
++ rpmlog(RPMLOG_ERR, "digest_list: could not apply security.ima "
++ "on '%s': %s\n", path, strerror(errno));
++ else
++ rpmlog(RPMLOG_DEBUG, "digest_list: security.ima successfully "
++ "applied on '%s'\n", path);
++out:
++ pgpDigParamsFree(sigp);
++ rpmtdFree(signature);
++ return ret;
++}
++
++static int fill_pgp_signature_header(rpmte te, struct signature_v2_hdr *sig_hdr)
++{
++ int ret = 0;
++ pgpDigParams sigp = NULL;
++ Header rpm = rpmteHeader(te);
++ rpmtd signature = rpmtdNew();
++
++ headerGet(rpm, RPMTAG_RSAHEADER, signature, 0);
++ ret = pgpPrtParams(signature->data, signature->count,
++ PGPTAG_SIGNATURE, &sigp);
++ if (ret) {
++ ret = -ENOENT;
++ goto out;
++ }
++
++ sig_hdr->type = EVM_IMA_XATTR_DIGSIG;
++ sig_hdr->version = 2;
++ sig_hdr->hash_algo = HASH_ALGO_SHA256;
++ memcpy((void *)&sig_hdr->keyid, sigp->signid + sizeof(uint32_t),
++ sizeof(uint32_t));
++out:
++ pgpDigParamsFree(sigp);
++ rpmtdFree(signature);
++ return ret;
++}
++
++static int write_digest_list_ima_xattr(rpmte te, char *path, char *path_sig)
++{
++ FD_t fd;
++ struct stat st;
++ int ret = 0, sig_size, hdr_exist;
++ uint8_t sig[2048] = { 0 };
++ struct signature_v2_hdr *sig_hdr = (struct signature_v2_hdr *)sig;
++
++ if (stat(path_sig, &st) == -1)
++ return -EACCES;
++
++ /* Check if the signature has already included a header */
++ hdr_exist = st.st_size % 128 == 0 ? 0 : 1;
++ if (!hdr_exist) {
++ ret = fill_pgp_signature_header(te, sig_hdr);
++ if (ret < 0)
++ return ret;
++ }
++
++ if (sizeof(sig_hdr) + st.st_size > sizeof(sig)) {
++ rpmlog(RPMLOG_ERR, "digest_list: signature in %s too big\n",
++ path);
++ return -E2BIG;
++ }
++
++ fd = Fopen(path_sig, "r.ufdio");
++ if (fd < 0) {
++ rpmlog(RPMLOG_ERR, "digest_list: could not open '%s': %s\n",
++ path_sig, strerror(errno));
++ return -EACCES;
++ }
++
++ sig_size = Fread(sig_hdr->sig, sizeof(uint8_t), st.st_size, fd);
++ if (sig_size != st.st_size || Ferror(fd)) {
++ rpmlog(RPMLOG_ERR, "digest_list: could not read '%s': %s\n",
++ path_sig, strerror(errno));
++ Fclose(fd);
++ return -EIO;
++ }
++
++ sig_hdr->sig_size = __cpu_to_be16(sig_size);
++ Fclose(fd);
++ rpmlog(RPMLOG_DEBUG,
++ "digest_list: read signature of %d bytes from '%s'\n",
++ sig_size, path_sig);
++
++ /* The signature may include the header */
++ if (hdr_exist)
++ ret = lsetxattr(path, XATTR_NAME_IMA, sig_hdr->sig, sig_size, 0);
++ else
++ ret = lsetxattr(path, XATTR_NAME_IMA, sig, sizeof(*sig_hdr) + sig_size, 0);
++
++ if (ret < 0)
++ rpmlog(RPMLOG_ERR, "digest_list: could not apply security.ima "
++ "on '%s': %s\n", path, strerror(errno));
++ else
++ rpmlog(RPMLOG_DEBUG, "digest_list: security.ima successfully "
++ "applied on '%s'\n", path);
++
++ return ret;
++}
++
++static int check_append_signature(const char *path)
++{
++ const char *magic_str="~Module signature appended~";
++ int magic_len = strlen(magic_str);
++ char buf[magic_len + 1];
++ FILE *fp = NULL;
++ struct stat st;
++ int file_size = 0;
++ int ret = 0;
++ long offset = 0;
++
++ if (stat(path, &st) == -1)
++ return 0;
++
++ file_size = st.st_size;
++
++ /* the character \0xa is append to MAGIC */
++ offset = magic_len + 1;
++ if (file_size < offset) {
++ rpmlog(RPMLOG_DEBUG, "digest_list: not have sig, do nothing\n");
++ return 0;
++ }
++
++ fp = fopen(path, "rb+");
++ if (!fp) {
++ rpmlog(RPMLOG_ERR, "digest_list: could not open '%s': %s\n", path, strerror(errno));
++ return 0;
++ }
++
++ ret = fseek(fp, (-offset), SEEK_END);
++ if (ret) {
++ rpmlog(RPMLOG_ERR, "digest_list: seek file fail with %s\n", strerror(errno));
++ fclose(fp);
++ return 0;
++ }
++
++ ret = fread(buf, 1, magic_len, fp);
++ if (ret == magic_len) {
++ if (strncmp(buf, magic_str, magic_len) == 0) {
++ fclose(fp);
++ return 1;
++ }
++ }
++
++ fclose(fp);
++ return 0;
++}
++
++static int process_digest_list(rpmte te, int parser, int pre)
++{
++ char *path = NULL, *path_sig = NULL;
++ int digest_list_signed = 0;
++ int digest_list_signed_append = 0;
++ struct stat st;
++ ssize_t size;
++ int type = rpmteType(te);
++ struct __user_cap_header_struct cap_header_data;
++ cap_user_header_t cap_header = &cap_header_data;
++ struct __user_cap_data_struct cap_data_data;
++ cap_user_data_t cap_data = &cap_data_data;
++ rpmRC ret = RPMRC_OK;
++
++ path = malloc(PATH_MAX);
++ if (!path) {
++ ret = RPMRC_FAIL;
++ goto out;
++ }
++
++ path_sig = malloc(PATH_MAX);
++ if (!path_sig) {
++ ret = RPMRC_FAIL;
++ goto out;
++ }
++
++ if (parser)
++ snprintf(path_sig, PATH_MAX,
++ "%s.sig/0-parser_list-compact-libexec.sig",
++ DIGEST_LIST_DEFAULT_PATH);
++ else
++ snprintf(path_sig, PATH_MAX,
++ "%s.sig/0-metadata_list-compact-%s-%s-%s.%s.sig",
++ DIGEST_LIST_DEFAULT_PATH, rpmteN(te), rpmteV(te),
++ rpmteR(te), rpmteA(te));
++
++ if (!stat(path_sig, &st)) {
++ digest_list_signed = 1;
++ rpmlog(RPMLOG_DEBUG, "digest_list: digest_list_signed = 1\n");
++ } else {
++ rpmlog(RPMLOG_DEBUG, "digest_list: digest_list_signed = 0\n");
++ }
++
++ if (parser && !digest_list_signed) {
++ rpmlog(RPMLOG_DEBUG, "digest_list: parser has to be signed!");
++ goto out;
++ }
++
++ if (parser)
++ snprintf(path, PATH_MAX, "%s/0-parser_list-compact-libexec",
++ DIGEST_LIST_DEFAULT_PATH);
++ else
++ snprintf(path, PATH_MAX,
++ "%s/0-metadata_list-compact-%s-%s-%s.%s",
++ DIGEST_LIST_DEFAULT_PATH, rpmteN(te), rpmteV(te),
++ rpmteR(te), rpmteA(te));
++
++ if (stat(path, &st) == -1) {
++ rpmlog(RPMLOG_DEBUG, "digest_list: failed to find digest list file path!");
++ goto out;
++ }
++
++ if (!digest_list_signed && check_append_signature(path)) {
++ digest_list_signed = 1;
++ digest_list_signed_append = 1;
++ }
++
++ if (!parser && !digest_list_signed)
++ snprintf(path, PATH_MAX, "%s/0-metadata_list-rpm-%s-%s-%s.%s",
++ DIGEST_LIST_DEFAULT_PATH, rpmteN(te), rpmteV(te),
++ rpmteR(te), rpmteA(te));
++
++ size = lgetxattr(path, XATTR_NAME_IMA, NULL, 0);
++
++ if (type == TR_ADDED && !pre && size < 0) {
++ if (!digest_list_signed) {
++ /* Write RPM header to the disk */
++ ret = write_rpm_digest_list(te, path);
++ if (ret < 0) {
++ ret = RPMRC_FAIL;
++ goto out;
++ }
++ }
++
++ /* don't call lsetxattr without CAP_SYS_ADMIN */
++ cap_header->pid = getpid();
++ cap_header->version = _LINUX_CAPABILITY_VERSION_1;
++ if (capget(cap_header, cap_data) < 0) {
++ ret = -ENOENT;
++ goto out;
++ }
++ if (!(cap_data->effective & CAP_TO_MASK(CAP_SYS_ADMIN))) {
++ ret = -EPERM;
++ goto out;
++ }
++
++ if (!digest_list_signed) {
++ /* Write RPM header sig to security.ima */
++ ret = write_rpm_digest_list_ima_xattr(te, path);
++ } else if (digest_list_signed_append) {
++ ret = RPMRC_OK;
++ } else {
++ ret = write_digest_list_ima_xattr(te, path, path_sig);
++ }
++
++ if (ret < 0) {
++ ret = RPMRC_FAIL;
++ goto out;
++ }
++ } else if (type == TR_ADDED && pre) {
++ if (size < 0)
++ goto out;
++
++ /* rpm is overwriting the digest list, remove from the kernel */
++ type = TR_REMOVED;
++ }
++
++ /* Upload digest list to securityfs */
++ upload_digest_list(path, type, digest_list_signed);
++
++ if (type == TR_REMOVED) {
++ if (!digest_list_signed) {
++ unlink(path);
++ goto out;
++ }
++ }
++out:
++ free(path);
++ free(path_sig);
++ return ret;
++}
++
++rpmte cur_te;
++int digest_list_counter;
++
++static rpmRC digest_list_psm_pre(rpmPlugin plugin, rpmte te)
++{
++ Header rpm = rpmteHeader(te);
++ rpmtd dirnames, dirindexes;
++ int i = -1;
++
++ digest_list_counter = 0;
++
++ dirnames = rpmtdNew();
++ headerGet(rpm, RPMTAG_DIRNAMES, dirnames, 0);
++
++ while ((i = rpmtdNext(dirnames)) >= 0) {
++ char *dirname = (char *) rpmtdGetString(dirnames);
++
++ if (!strncmp(dirname, DIGEST_LIST_DEFAULT_PATH,
++ sizeof(DIGEST_LIST_DEFAULT_PATH) - 1) &&
++ dirname[sizeof(DIGEST_LIST_DEFAULT_PATH) - 1] == '/')
++ break;
++ }
++
++ rpmtdFree(dirnames);
++
++ if (i == -1)
++ return RPMRC_OK;
++
++ dirindexes = rpmtdNew();
++ headerGet(rpm, RPMTAG_DIRINDEXES, dirindexes, 0);
++ while (rpmtdNext(dirindexes) >= 0)
++ if (rpmtdGetNumber(dirindexes) == i)
++ digest_list_counter++;
++
++ rpmtdFree(dirindexes);
++
++ cur_te = te;
++ return RPMRC_OK;
++}
++
++static rpmRC digest_list_file_common(rpmPlugin plugin, rpmfi fi,
++ const char* path, mode_t file_mode,
++ rpmFsmOp op, int pre, int res)
++{
++ rpmFileAction action = XFO_ACTION(op);
++
++ if (!digest_list_counter)
++ return RPMRC_OK;
++
++ if (!cur_te)
++ return RPMRC_OK;
++
++ if (!pre && res != RPMRC_OK)
++ return res;
++
++ if (!pre && rpmteType(cur_te) != TR_ADDED)
++ return RPMRC_OK;
++
++ if (pre && action == FA_SKIP)
++ return RPMRC_OK;
++
++ if (path == NULL || strncmp(path, DIGEST_LIST_DEFAULT_PATH,
++ sizeof(DIGEST_LIST_DEFAULT_PATH) - 1) ||
++ path[sizeof(DIGEST_LIST_DEFAULT_PATH) - 1] != '/')
++ return RPMRC_OK;
++
++ if (!pre && --digest_list_counter)
++ return RPMRC_OK;
++
++ rpmlog(RPMLOG_DEBUG, "process ima digest, pre: %d, action: %d, teType: %d\n",
++ pre, action, rpmteType(cur_te));
++ process_digest_list(cur_te, 0, pre);
++ if (!strcmp(rpmteN(cur_te), "digest-list-tools")) {
++ if (pre && rpmteType(cur_te) == TR_REMOVED)
++ return RPMRC_OK;
++
++ rpmlog(RPMLOG_DEBUG, "process parser digest\n");
++ process_digest_list(cur_te, 1, pre);
++ }
++
++ return RPMRC_OK;
++}
++
++static rpmRC digest_list_file_pre(rpmPlugin plugin, rpmfi fi,
++ const char* path, mode_t file_mode,
++ rpmFsmOp op)
++{
++ return digest_list_file_common(plugin, fi, path, file_mode, op, 1, 0);
++}
++
++static rpmRC digest_list_file_post(rpmPlugin plugin, rpmfi fi,
++ const char* path, mode_t file_mode,
++ rpmFsmOp op, int res)
++{
++ return digest_list_file_common(plugin, fi, path, file_mode, op, 0, res);
++}
++
++struct rpmPluginHooks_s digest_list_hooks = {
++ .psm_pre = digest_list_psm_pre,
++ .fsm_file_pre = digest_list_file_pre,
++ .fsm_file_post = digest_list_file_post,
++};
+--
+2.46.0
+