[Rpm-maint] [PATCH 07/12] Add rpmpols struct plus some helper functions
Steve Lawrence
slawrence at tresys.com
Thu Oct 22 18:25:44 UTC 2009
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 | 442 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/rpmpol.h | 88 +++++++++++
lib/rpmtypes.h | 1 +
3 files changed, 531 insertions(+), 0 deletions(-)
diff --git a/lib/rpmpol.c b/lib/rpmpol.c
index 18b8419..a0e8990 100644
--- a/lib/rpmpol.c
+++ b/lib/rpmpol.c
@@ -11,6 +11,7 @@
#include <rpm/rpmlog.h>
#include <rpm/rpmfileutil.h>
#include <rpm/rpmmacro.h>
+#include <rpm/rpmdb.h>
#include "rpmio/base64.h"
@@ -31,6 +32,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 */
@@ -401,6 +410,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));
@@ -452,6 +518,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;
@@ -657,3 +760,342 @@ 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)) {
+ rpmpolFree(pol);
+ continue;
+ }
+
+ 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) {
+ action = RPMPOL_ACTION_IGNORE;
+ } else if (cur) {
+ action = RPMPOL_ACTION_UPGRADE;
+ changes = 1;
+ } else {
+ 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)) {
+ argvAdd(&ps->obsoleted, *cur);
+ changes = 1;
+ }
+ }
+ }
+
+ if (changes == 0) {
+ rc = RPMRC_NOTFOUND;
+ goto exit;
+ }
+
+ rc = RPMRC_OK;
+
+exit:
+ h = headerFree(h);
+ 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, const char * root, const char * cwd)
+{
+ rpmpoltrans ptrans = NULL;
+ rpmRC rc = RPMRC_FAIL;
+ int chrootDone = 0;
+ char * fcpath;
+
+ 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;
+ }
+
+ matchpathcon_fini();
+ fcpath = rpmGetPath("%{?_install_file_context_path}", NULL);
+ if (matchpathcon_init(fcpath) == -1) {
+ rpmlog(RPMLOG_WARNING, _("Failed to read new file contexts. New files may be mislabeled.\n"));
+ }
+ _free(fcpath);
+
+err:
+ ptrans = rpmpoltransFree(ptrans);
+
+ if (chrootDone) {
+ chroot(".");
+ chdir(cwd);
+ }
+
+ return rc;
+}
diff --git a/lib/rpmpol.h b/lib/rpmpol.h
index 985f761..4c3489d 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"
/** \ingroup rpmpol
* Unreference a policy set instance.
@@ -176,6 +177,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
@@ -194,6 +205,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
@@ -238,6 +258,74 @@ 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 root root directory
+ * @param cwd current working directory
+ * @return RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+RPM_GNUC_INTERNAL
+rpmRC rpmpolsInstall(rpmpols ps, const char * root, const char * cwd);
#ifdef __cplusplus
}
diff --git a/lib/rpmtypes.h b/lib/rpmtypes.h
index 86b2b01..8ba0df8 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 const void * fnpyKey;
--
1.6.0.6
More information about the Rpm-maint
mailing list