[Rpm-maint] [PATCH 07/19] Add rpmpols struct plus some helper functions
Steve Lawrence
slawrence at tresys.com
Tue Feb 2 20:25:10 UTC 2010
The policy set structure stores information about all the policies and is
used to perform various checks and preparations for the policy installation.
The order in which the functions should be called (and their purpose) is as follows:
rpmpolsNew
Create an empty rpmpols structure
rpmpolsAdd
Add rpmpol structures to the policy set
rpmpolsSetType
Set the type of policy to deal with
rpmpolsPrepare
Calculate the actions to take on the rpmpol structures. Base on what is
currently installed and what is obsoleted, policies are assigned actions
(upgrade/install/etc). These actions are later used during the policy
transaction to determine how what and how policies should be installed.
rpmpolsInstall
Create a new policy transaction, add the policies to the transaction
(based on their actions) and finally commit the transaction, installing
all policies.
rpmpolsSaveStave
Save the policies changes to the rpm database. Due to security reasons,
policy is not removed when the package that installed it is removed. Because
of this, we need a way to keep track of which policies have been installed
and their properties. To accomplish this, we create pseudo packages
(akin to gpg-pubkey) containing the necessary information and update the
rpm database.
rpmpolsFree
Clean up the rpmols structure
---
lib/rpmpol.c | 445 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/rpmpol.h | 87 +++++++++++
lib/rpmtypes.h | 1 +
3 files changed, 533 insertions(+), 0 deletions(-)
diff --git a/lib/rpmpol.c b/lib/rpmpol.c
index 3515e82..85e5368 100644
--- a/lib/rpmpol.c
+++ b/lib/rpmpol.c
@@ -17,6 +17,9 @@
#include <rpm/rpmlog.h>
#include <rpm/rpmfileutil.h>
#include <rpm/rpmmacro.h>
+#include <rpm/rpmdb.h>
+#include <rpm/rpmds.h>
+#include <rpm/rpmts.h>
#include "rpmio/base64.h"
@@ -37,6 +40,14 @@ struct rpmpol_s {
int index; /*!< index for iterator */
};
+struct rpmpols_s {
+ char * type;
+ rpmpol * pols; /*!< array of rpmpols */
+ ARGV_t obsoleted; /*!< list of obsoleted policies */
+ unsigned int count; /*!< number of rpmpols */
+ size_t capacity; /*!< alloced size */
+};
+
struct rpmpoltrans_s {
char * semodulepath; /*!< path to semodule binary */
int execsemodule; /*!< 0 = use libsemanage to install policy; non-zero = use semodule */
@@ -407,6 +418,63 @@ exit:
return rc;
}
+Header rpmpolMakeHeader(const rpmpol pol, const char * type, rpm_tid_t tid)
+{
+ Header h = NULL;
+ uint32_t zero = 0;
+ const char * data;
+ const char * name;
+ uint32_t flags;
+ ARGV_const_t types;
+ ARGV_const_t obs;
+ ARGV_const_t arg;
+
+ if (!pol || !rpmpolIsValidIndex(pol) || !type) {
+ goto exit;
+ }
+
+ data = rpmpolGetData(pol);
+ name = rpmpolGetName(pol);
+ flags = rpmpolGetFlags(pol);
+ types = rpmpolGetTypes(pol);
+ obs = rpmpolGetObsoletes(pol);
+
+ if (!data || !name || !types) {
+ goto exit;
+ }
+
+ h = headerNew();
+
+ /* package name = RPMPOL_PKG_NAME-<type>-<name> */
+ headerPutString(h, RPMTAG_NAME, RPMPOL_PKG_NAME);
+ headerPutString(h, RPMTAG_VERSION, type);
+ headerPutString(h, RPMTAG_RELEASE, name);
+
+ headerPutString(h, RPMTAG_POLICIES, data);
+ headerPutString(h, RPMTAG_POLICYNAMES, name);
+ headerPutUint32(h, RPMTAG_POLICYFLAGS, &flags, 1);
+
+ for (arg = types; arg && *arg; arg++) {
+ headerPutString(h, RPMTAG_POLICYTYPES, *arg);
+ headerPutUint32(h, RPMTAG_POLICYTYPESINDEXES, &zero, 1);
+ }
+
+ for (arg = obs; arg && *arg; arg++) {
+ headerPutString(h, RPMTAG_POLICYOBSOLETES, *arg);
+ headerPutUint32(h, RPMTAG_POLICYOBSOLETESBY, &zero, 1);
+ }
+
+ headerPutUint32(h, RPMTAG_SIZE, &zero, 1);
+ headerPutUint32(h, RPMTAG_BUILDTIME, &tid, 1);
+ headerPutUint32(h, RPMTAG_INSTALLTIME, &tid, 1);
+ headerPutString(h, RPMTAG_RPMVERSION, RPMVERSION);
+ headerPutString(h, RPMTAG_BUILDHOST, "localhost");
+ headerPutString(h, RPMTAG_SOURCERPM, "(none)");
+
+exit:
+ return h;
+}
+
rpmpoltrans rpmpoltransBegin(int chroot, const char * type)
{
rpmpoltrans pt = xcalloc(1, sizeof(*pt));
@@ -458,6 +526,43 @@ err:
return pt;
}
+rpmRC rpmpoltransAddSet(rpmpoltrans pt, rpmpols ps)
+{
+ rpmRC rc = RPMRC_FAIL;
+ ARGV_const_t obs;
+ unsigned int i;
+
+ if (!pt || !ps) {
+ return rc;
+ }
+
+ /* remove all obsoleted policies */
+ for (obs = ps->obsoleted; obs && *obs; obs++) {
+ rc = rpmpoltransRemove(pt, *obs);
+ if (rc != RPMRC_OK) {
+ goto exit;
+ }
+ }
+
+ /* add the to-be-installed policies */
+ for (i = 0; i < ps->count; i++) {
+ rpmpol pol = ps->pols[i];
+
+ rpmpolInitIterator(pol);
+ while (rpmpolNext(pol) >= 0) {
+ rc = rpmpoltransAdd(pt, pol);
+ if (rc != RPMRC_OK) {
+ goto exit;
+ }
+ }
+ }
+
+ rc = RPMRC_OK;
+
+exit:
+ return rc;
+}
+
rpmRC rpmpoltransAdd(rpmpoltrans pt, rpmpol pol)
{
char * path = NULL;
@@ -667,4 +772,344 @@ rpmpoltrans rpmpoltransFree(rpmpoltrans pt)
pt = _free(pt);
return NULL;
}
+
+rpmpols rpmpolsNew(void)
+{
+ rpmpols ps = xcalloc(1, sizeof(*ps));
+ ps->type = NULL;
+ ps->obsoleted = NULL;
+ ps->count = 0;
+ ps->capacity = 16;
+ ps->pols = xcalloc(ps->capacity, sizeof(*ps->pols));
+ return ps;
+}
+
+rpmpols rpmpolsFree(rpmpols ps)
+{
+ unsigned int i;
+
+ if (!ps) {
+ return NULL;
+ }
+
+ for (i = 0; i < ps->count; i++) {
+ ps->pols[i] = rpmpolFree(ps->pols[i]);
+ }
+ ps->pols = _free(ps->pols);
+ ps->type = _free(ps->type);
+ ps->obsoleted = argvFree(ps->obsoleted);
+ ps = _free(ps);
+ return NULL;
+}
+
+rpmRC rpmpolsAdd(rpmpols ps, rpmpol pol)
+{
+ if (!ps || !pol) {
+ return RPMRC_FAIL;
+ }
+
+ if (ps->count == ps->capacity) {
+ ps->capacity *= 2;
+ ps->pols = xrealloc(ps->pols, ps->capacity);
+ }
+
+ ps->pols[ps->count] = rpmpolLink(pol);
+ ps->count++;
+
+ return RPMRC_OK;
+}
+
+void rpmpolsSetType(rpmpols ps, const char * type)
+{
+ ps->type = xstrdup(type);
+}
+
+const char * rpmpolsGetType(rpmpols ps)
+{
+ return ps ? ps->type : NULL;
+}
+
+/*
+ * Determine whether to install/udpate/remove/etc each rpmpol element
+ *
+ * First, we essentially get three sets: Obsoletes Policies, Currently
+ * Installed Policies, and Policies to be installed by this rpm
+ * transaction. The set of obsoleted policies contains policies
+ * obsoleted by currently installed policies as well as policies obsoleted
+ * by to be installed policies.
+ *
+ * With these three sets, below is how we determine what action to take on
+ * the policies:
+ *
+ * `:::::::::::::- .:::::::::::::-
+ * `//- `+ss- .:/-
+ * `/: `+: `/: ./-
+ * -+` :/ .o` -+
+ * -+ Obsoleted :/ `o` Currently .o
+ * s Policies `o .o Installed -/
+ * :: +. R o` Policies s
+ * +` o +. o
+ * :- X o/::::::::::y:` X s
+ * `o -/:-+ `o`-//` -/
+ * -/ -/. /: X/R o` :/` `o
+ * -+ +- // `o` `+- .+
+ * `+: o` X .+- `// U /- `/:
+ * .//. /- +sy. o.:/:
+ * .:h:::----:::::` -::::--.--:::+o`
+ * o ```` ```` o
+ * s .+
+ * +. To-Be-Installed o`
+ * s` Policies :/
+ * `o. /:
+ * //` I -+.
+ * `:/- `:/-
+ * `:::::-...-::::-
+ * `..``
+ * I - Install
+ * U - Upgrade
+ * R - Remove
+ * X - Do Nothing/Ignore/Don't Install
+ *
+ * Note: The center is marked as X/R because to-be-installed policies are
+ * ignored (not installed), but the policies are added to the list of curerntly
+ * installed policies to remove (this prevents removing a policy module twice)
+ */
+rpmRC rpmpolsPrepare(rpmpols ps, rpmdb db)
+{
+ rpmpol pol;
+ Header h = NULL;
+ rpmdbMatchIterator mi = NULL;
+ ARGV_t obsList = NULL;
+ ARGV_t curList = NULL;
+ ARGV_t obs;
+ ARGV_t cur;
+ int changes = 0;
+ unsigned int i;
+ rpmRC rc = RPMRC_FAIL;
+
+ if (!ps || !db) {
+ return rc;
+ }
+
+ if(ps->count == 0) {
+ return RPMRC_NOTFOUND;
+ }
+
+ /* generate list of policies obsoleted by the to-be-installed policies */
+ for (i = 0; i < ps->count; i++) {
+ pol = ps->pols[i];
+
+ rpmpolInitIterator(pol);
+ while (rpmpolNext(pol) >= 0) {
+ if (!rpmpolHasType(pol, ps->type)) {
+ continue;
+ }
+ argvAppend(&obsList, rpmpolGetObsoletes(pol));
+ }
+ }
+
+ /* generate list of currently installed policies and what they obsolete */
+ mi = rpmdbInitIterator(db, RPMTAG_NAME, RPMPOL_PKG_NAME, 0);
+ rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP, ps->type);
+ while ((h = rpmdbNextIterator(mi)) != NULL) {
+ pol = rpmpolNew(h);
+ if (!pol) {
+ rpmlog(RPMLOG_ERR, _("Corrupt policy-module found in database"));
+ goto exit;
+ }
+ rpmpolInitIterator(pol);
+ rpmpolNext(pol); /* there is only one rpmpol in a RPMPOL_PKG_NAME */
+
+ if (rpmpolHasType(pol, ps->type)) {
+ argvAdd(&curList, rpmpolGetName(pol));
+ argvAppend(&obsList, rpmpolGetObsoletes(pol));
+ }
+
+ rpmpolFree(pol);
+ }
+ mi = rpmdbFreeIterator(mi);
+
+ argvSort(curList, NULL);
+ argvSort(obsList, NULL);
+
+ /* determine the actions for all the policies to be installed */
+ for (i = 0; i < ps->count; i++) {
+ pol = ps->pols[i];
+ if (!pol) {
+ goto exit;
+ }
+
+ rpmpolInitIterator(pol);
+ while (rpmpolNext(pol) >= 0) {
+ int action;
+ const char * name;
+
+ if (!rpmpolHasType(pol, ps->type)) {
+ rpmpolSetAction(pol, RPMPOL_ACTION_IGNORE);
+ continue;
+ }
+
+ name = rpmpolGetName(pol);
+ cur = argvSearch(curList, name, NULL);
+ obs = argvSearch(obsList, name, NULL);
+
+ if (obs) {
+ rpmlog(RPMLOG_DEBUG, "ignoring policy module: %s\n", name);
+ action = RPMPOL_ACTION_IGNORE;
+ } else if (cur) {
+ rpmlog(RPMLOG_DEBUG, "upgrading policy module: %s\n", name);
+ action = RPMPOL_ACTION_UPGRADE;
+ changes = 1;
+ } else {
+ rpmlog(RPMLOG_DEBUG, "installing policy module: %s\n", name);
+ action = RPMPOL_ACTION_INSTALL;
+ changes = 1;
+ }
+
+ rpmpolSetAction(pol, action);
+ }
+ }
+
+ /* remember currently installed policies that have been obsoleted for removal */
+ for (obs = obsList; obs && *obs; obs++) {
+ for (cur = curList; cur && *cur; cur++) {
+ if (!strcmp(*cur, *obs)) {
+ rpmlog(RPMLOG_DEBUG, "removing policy module: %s\n", *cur);
+ argvAdd(&ps->obsoleted, *cur);
+ changes = 1;
+ }
+ }
+ }
+
+ if (changes == 0) {
+ rc = RPMRC_NOTFOUND;
+ goto exit;
+ }
+
+ rc = RPMRC_OK;
+
+exit:
+ rpmdbFreeIterator(mi);
+ obsList = argvFree(obsList);
+ curList = argvFree(curList);
+
+ return rc;
+}
+
+rpmRC rpmpolsSaveState(rpmpols ps, rpmdb db, rpm_tid_t tid)
+{
+ Header h;
+ rpmpol pol;
+ unsigned int i;
+ ARGV_const_t obs;
+
+ if (!ps || !db) {
+ return RPMRC_FAIL;
+ }
+
+ /* remove obsoleted policies from the database */
+ for (obs = ps->obsoleted; obs && *obs; obs++) {
+ rpmdbMatchIterator mi = rpmdbInitIterator(db, RPMTAG_NAME, RPMPOL_PKG_NAME, 0);
+ rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP, ps->type);
+ rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP, *obs);
+ while ((h = rpmdbNextIterator(mi)) != NULL) {
+ rpmdbRemove(db, tid, headerGetInstance(h), NULL, NULL);
+ }
+ rpmdbFreeIterator(mi);
+ }
+
+ for (i = 0; i < ps->count; i++) {
+ pol = ps->pols[i];
+
+ rpmpolInitIterator(pol);
+ while (rpmpolNext(pol) >= 0) {
+ rpmpolAction action = rpmpolGetAction(pol);
+
+ if (action == RPMPOL_ACTION_IGNORE) {
+ continue;
+ }
+
+ if (action == RPMPOL_ACTION_REMOVE || action == RPMPOL_ACTION_UPGRADE) {
+ rpmdbMatchIterator mi = rpmdbInitIterator(db, RPMTAG_NAME, RPMPOL_PKG_NAME, 0);
+ rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP, ps->type);
+ rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP, rpmpolGetName(pol));
+ while ((h = rpmdbNextIterator(mi)) != NULL) {
+ rpmdbRemove(db, tid, headerGetInstance(h), NULL, NULL);
+ }
+ rpmdbFreeIterator(mi);
+ }
+
+ if (action == RPMPOL_ACTION_INSTALL || action == RPMPOL_ACTION_UPGRADE) {
+ h = rpmpolMakeHeader(pol, ps->type, tid);
+ rpmdbAdd(db, tid, h, NULL, NULL);
+ headerFree(h);
+ }
+ }
+ }
+
+ return RPMRC_OK;
+}
+
+rpmRC rpmpolsInstall(rpmpols ps, rpmts ts)
+{
+ rpmpoltrans ptrans = NULL;
+ rpmRC rc = RPMRC_FAIL;
+ int chrootDone = 0;
+ const char * root = rpmtsRootDir(ts);
+ const char * cwd = rpmtsCurrDir(ts);
+
+ if (!ps || (root && !cwd)) {
+ return rc;
+ }
+
+ int dochroot = (root != NULL && !rstreq(root, "/") && *root == '/');
+ if (dochroot) {
+ if (chdir("/") == -1) {
+ rpmlog(RPMLOG_ERR, _("Failed to chdir: %s\n"), strerror(errno));
+ rc = RPMRC_FAIL;
+ goto err;
+ }
+
+ if (chroot(root) == -1) {
+ rpmlog(RPMLOG_ERR, _("Failed to chroot: %s\n"), strerror(errno));
+ rc = RPMRC_FAIL;
+ goto err;
+ }
+
+ chrootDone = 1;
+ }
+
+ ptrans = rpmpoltransBegin(chrootDone, rpmpolsGetType(ps));
+ if (!ptrans) {
+ rc = RPMRC_FAIL;
+ goto err;
+ }
+
+ rc = rpmpoltransAddSet(ptrans, ps);
+ if (rc != RPMRC_OK) {
+ goto err;
+ }
+
+ rc = rpmpoltransCommit(ptrans);
+ if (rc != RPMRC_OK) {
+ goto err;
+ }
+
+ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) {
+ matchpathcon_fini();
+ if (matchpathcon_init(selinux_file_context_path()) == -1) {
+ rpmlog(RPMLOG_WARNING, _("Failed to read new file contexts. New files may be mislabeled.\n"));
+ }
+ }
+
+err:
+ ptrans = rpmpoltransFree(ptrans);
+
+ if (chrootDone) {
+ chroot(".");
+ chdir(cwd);
+ }
+
+ return rc;
+}
#endif /* WITH_SELINUX */
diff --git a/lib/rpmpol.h b/lib/rpmpol.h
index 1902238..eb588dd 100644
--- a/lib/rpmpol.h
+++ b/lib/rpmpol.h
@@ -25,6 +25,7 @@ typedef enum rpmpolFlags_e {
} rpmpolFlags;
#define RPMPOL_TYPE_DEFAULT "default"
+#define RPMPOL_PKG_NAME "policy-module"
#if WITH_SELINUX
@@ -178,6 +179,16 @@ RPM_GNUC_INTERNAL
int rpmpolIsValidIndex(const rpmpol pol);
/** \ingroup rpmpol
+ * Create a header than can be used to create a faux policy package
+ * @param pol rpm policy element
+ * @param type policy type
+ * @param tid rpm transaction id
+ * @return new header, or NULL on failure. caller must free return header if not null
+ */
+RPM_GNUC_INTERNAL
+Header rpmpolMakeHeader(const rpmpol pol, const char * type, rpm_tid_t tid);
+
+/** \ingroup rpmpol
* Begin an rpm policy transaction
* @param chroot boolean, is the policy being installed in a chroot? 0 for no, non-zero for yes
* @param type type to install to during the transaction, or NULL to use the default
@@ -196,6 +207,15 @@ RPM_GNUC_INTERNAL
rpmRC rpmpoltransAdd(rpmpoltrans pt, rpmpol pol);
/** \ingroup rpmpol
+ * Add an rpm policy set to an rpm policy transaction
+ * @param pt rpm policy transaction
+ * @param ps rpm policy set
+ * @return RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+RPM_GNUC_INTERNAL
+rpmRC rpmpoltransAddSet(rpmpoltrans pt, rpmpols ps);
+
+/** \ingroup rpmpol
* Commit the rpm policy transaction
* @param pt rpm policy transaction
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
@@ -240,6 +260,73 @@ rpmRC rpmpoltransInstallBase(rpmpoltrans pt, const char * path, const char * nam
RPM_GNUC_INTERNAL
rpmRC rpmpoltransRemove(rpmpoltrans pt, const char * name);
+/** \ingroup rpmpol
+ * Create an empty policy set
+ * @return empty policy set
+ */
+RPM_GNUC_INTERNAL
+rpmpols rpmpolsNew(void);
+
+/** \ingroup rpmpol
+ * Free a policy set
+ * @param ps rpm policy set
+ * @return NULL
+ */
+RPM_GNUC_INTERNAL
+rpmpols rpmpolsFree(rpmpols ps);
+
+/** \ingroup rpmpol
+ * Add a policy element to a policy set
+ * @param ps rpm policy set
+ * @param pol
+ * @return RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+RPM_GNUC_INTERNAL
+rpmRC rpmpolsAdd(rpmpols ps, rpmpol pol);
+
+/** \ingroup rpmpol
+ * Set the type the policy set should use for dependency checks
+ * @param ps rpm policy set
+ * @param type policy type
+ */
+RPM_GNUC_INTERNAL
+void rpmpolsSetType(rpmpols ps, const char * type);
+
+/** \ingroup rpmpol
+ * Get the type of the policy set
+ * @param ps rpm policy set
+ * @return type of policy set
+ */
+RPM_GNUC_INTERNAL
+const char * rpmpolsGetType(rpmpols ps);
+
+/** \ingroup rpmpol
+ * Set the actions on the policies
+ * @param ps rpm policy set
+ * @param db rpm database
+ * @return RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+RPM_GNUC_INTERNAL
+rpmRC rpmpolsPrepare(rpmpols ps, rpmdb db);
+
+/** \ingroup rpmpol
+ * Write the policy set to the rpm database
+ * @param ps rpm policy set
+ * @param db rpm database
+ * @param tid rpm transaction id
+ * @return RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+RPM_GNUC_INTERNAL
+rpmRC rpmpolsSaveState(rpmpols ps, rpmdb db, rpm_tid_t tid);
+
+/** \ingroup rpmpol
+ * Install policy from a policy set
+ * @param ps rpm policy set
+ * @param ts rpm transaction set
+ * @return RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+RPM_GNUC_INTERNAL
+rpmRC rpmpolsInstall(rpmpols ps, rpmts ts);
#ifdef __cplusplus
}
diff --git a/lib/rpmtypes.h b/lib/rpmtypes.h
index f2a0509..939ff5b 100644
--- a/lib/rpmtypes.h
+++ b/lib/rpmtypes.h
@@ -62,6 +62,7 @@ typedef struct rpmds_s * rpmds;
typedef struct rpmfi_s * rpmfi;
typedef struct rpmdb_s * rpmdb;
typedef struct rpmpol_s * rpmpol;
+typedef struct rpmpols_s * rpmpols;
typedef struct rpmpoltrans_s * rpmpoltrans;
typedef struct rpmdbMatchIterator_s * rpmdbMatchIterator;
typedef struct rpmtsi_s * rpmtsi;
--
1.6.2.5
More information about the Rpm-maint
mailing list