Hi,

Following up our recent discussion, I have composed a first patch in order
not to talk about the abstract concepts only.
I have taken the less intrusive approach and tried to integrate the new
hooks and the notion of "security plugin"
 into the code with least amount of changes for core rpm and for existing
collection hooks.  This would also allow to leave the existing
SELinux collection hooks as they are and only move the integrated SElinux
functionality from rpm to the hooks. 

Please note that this patch is very rough and I would like to post it only
for the purpose of asking if this approach is valid. 
There are a number of decisions that I had to make about this patch that are
worth discussing: 

- The patch defines a new type of rpm plugin, called security plugin and add
a rpmpluginsAddSecurityPlugin() function to initialize it.
This is done in the similar style as rpmpluginsAddCollectionPlugin()
function. The top level function that uses it is rpmteSetupSecurityPlugins()
from transaction.c. The main difference from the collection plugin case is
that this function can automatically discover the security plugins
that should be loaded based on the %__security_plugins macro from macros.in
that contains comma separated list of security plugins to be loaded. 
I don't know how viable this approach is, but it seemed for me the easiest
way to make the plugins to be configured. 

-Due to necessity of calling the plugins hooks with the plugin struct that
is stored in ts, some rpm functions have to pass the rpmts struct. 
In addition since the ts->plugins is the actual needed parameter,
ts_internal.h has to be exposed to couple of more .c file. I find it to be
quite 
ugly, but could not figure out the better way with the current plugin
definition. I was especially annoyed by the script functions that now have
to pass ts, too.
Any suggestion on this?

- Instead of making a loop for each plugin hook to be called for each
plugin, I am iterating by the plugins and calling the hook for each plugin
inside the rpmpluginsCallxxx() functions. IMO it makes the hook code
scattered through the rpm cleaner, but this is just my opinion. 

>From 0c04ff99a00e747899137be41dca5eae72e423e4 Mon Sep 17 00:00:00 2001
From: Elena Reshetova <elena.reshet...@intel.com>
Date: Mon, 8 Oct 2012 14:21:53 +0300
Subject: [PATCH] Extending the plugin interface

---
 lib/fsm.c                   |   42 ++++++--
 lib/package.c               |   14 ++-
 lib/psm.c                   |    2 +-
 lib/rpmplugins.c            |  228
+++++++++++++++++++++++++++++++++++++++++++
 lib/rpmplugins.h            |  136 +++++++++++++++++++++++++-
 lib/rpmscript.c             |   18 ++--
 lib/rpmscript.h             |    2 +-
 lib/rpmte.c                 |   14 ++-
 lib/transaction.c           |   52 ++++++++++
 macros.in                   |    7 ++
 plugins/Makefile.am         |    5 +-
 plugins/plugin.h            |   22 +++++
 plugins/sec-sample-plugin.c |   82 ++++++++++++++++
 13 files changed, 599 insertions(+), 25 deletions(-)
 create mode 100644 plugins/sec-sample-plugin.c

diff --git a/lib/fsm.c b/lib/fsm.c
index 5ebf28d..e1cec85 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -718,11 +718,12 @@ static int fsmMapAttrs(FSM_t fsm)
 
 /** \ingroup payload
  * Create file from payload stream.
+ * @param ts           rpm transaction
  * @param fsm          file state machine data
  * @param archive      payload archive
  * @return             0 on success
  */
-static int expandRegular(FSM_t fsm, rpmpsm psm, rpmcpio_t archive, int
nodigest)
+static int expandRegular(rpmts ts, FSM_t fsm, rpmpsm psm, rpmcpio_t
archive, int nodigest)
 {
     FD_t wfd = NULL;
     const struct stat * st = &fsm->sb;
@@ -753,6 +754,13 @@ static int expandRegular(FSM_t fsm, rpmpsm psm,
rpmcpio_t archive, int nodigest)
             rc = CPIOERR_READ_FAILED;
            goto exit;
         }
+
+        /* Run file updated hook for all plugins */
+        rc = rpmpluginsCallFileUpdated(ts->plugins, fsm->path, fsm->buf,
len);
+        if (rc) {
+               goto exit;
+        }
+
        if ((Fwrite(fsm->buf, sizeof(*fsm->buf), len, wfd) != len) ||
Ferror(wfd)) {
            rc = CPIOERR_WRITE_FAILED;
            goto exit;
@@ -1050,14 +1058,15 @@ static int fsmMakeLinks(FSM_t fsm, hardLink_t li)
     return ec;
 }
 
-static int fsmCommit(FSM_t fsm, int ix);
+static int fsmCommit(rpmts ts, FSM_t fsm, int ix);
 
 /** \ingroup payload
  * Commit hard linked file set atomically.
+ * @param ts           rpm transaction
  * @param fsm          file state machine data
  * @return             0 on success
  */
-static int fsmCommitLinks(FSM_t fsm)
+static int fsmCommitLinks(rpmts ts, FSM_t fsm)
 {
     char * path = fsm->path;
     const char * nsuffix = fsm->nsuffix;
@@ -1078,7 +1087,7 @@ static int fsmCommitLinks(FSM_t fsm)
        if (li->filex[i] < 0) continue;
        rc = fsmMapPath(fsm, li->filex[i]);
        if (!XFA_SKIPPING(fsm->action))
-           rc = fsmCommit(fsm, li->filex[i]);
+           rc = fsmCommit(ts, fsm, li->filex[i]);
        fsm->path = _free(fsm->path);
        li->filex[i] = -1;
     }
@@ -1149,11 +1158,12 @@ static int fsmMknod(const char *path, mode_t mode,
dev_t dev)
 
 /**
  * Create (if necessary) directories not explicitly included in package.
+ * @param ts           rpm transaction
  * @param dnli         file state machine data
  * @param sehandle     selinux label handle (bah)
  * @return             0 on success
  */
-static int fsmMkdirs(rpmfi fi, rpmfs fs, struct selabel_handle *sehandle)
+static int fsmMkdirs(rpmts ts, rpmfi fi, rpmfs fs, struct selabel_handle
*sehandle)
 {
     DNLI_t dnli = dnlInitIterator(fi, fs, 0);
     struct stat sb;
@@ -1216,7 +1226,8 @@ static int fsmMkdirs(rpmfi fi, rpmfs fs, struct
selabel_handle *sehandle)
                rc = fsmMkdir(dn, mode);
                if (!rc) {
                    rc = fsmSetSELabel(sehandle, dn, mode);
-
+                    if (!rc)
+                        rc = rpmpluginsCallDirCreated(ts->plugins, dn,
mode);
                    rpmlog(RPMLOG_DEBUG,
                            "%s directory created with perms %04o\n",
                            dn, (unsigned)(mode & 07777));
@@ -1524,7 +1535,7 @@ static int fsmBackup(FSM_t fsm)
     return rc;
 }
 
-static int fsmCommit(FSM_t fsm, int ix)
+static int fsmCommit(rpmts ts, FSM_t fsm, int ix)
 {
     int rc = 0;
     struct stat * st = &fsm->sb;
@@ -1551,6 +1562,10 @@ static int fsmCommit(FSM_t fsm, int ix)
         if (!rc && !getuid()) {
             rc = fsmSetSELabel(fsm->sehandle, fsm->path, fsm->sb.st_mode);
         }
+        /* Run  file closed hook for all plugins */
+        if (!rc) {
+                rc = rpmpluginsCallFileClosed(ts->plugins, fsm->path);
+        }
         if (S_ISLNK(st->st_mode)) {
             if (!rc && !getuid())
                 rc = fsmLChown(fsm->path, fsm->sb.st_uid, fsm->sb.st_gid);
@@ -1645,7 +1660,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfi
fi, FD_t cfd,
 
     /* Detect and create directories not explicitly in package. */
     if (!rc) {
-       rc = fsmMkdirs(fi, rpmteGetFileStates(te), fsm->sehandle);
+       rc = fsmMkdirs(ts, fi, rpmteGetFileStates(te), fsm->sehandle);
     }
 
     while (!rc) {
@@ -1684,6 +1699,13 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfi
fi, FD_t cfd,
             break;
         }
 
+        /* Run file opened hook for all plugins  */
+       rc = rpmpluginsCallFileOpened(ts->plugins, fsm->path);
+       if (rc) {
+            fsm->postpone = 1;
+            break;
+       }
+
        if (S_ISREG(fsm->sb.st_mode) && fsm->sb.st_nlink > 1)
            fsm->postpone = saveHardLink(fsm, &li);
 
@@ -1693,7 +1715,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfi
fi, FD_t cfd,
             if (S_ISREG(st->st_mode)) {
                 rc = fsmVerify(fsm);
                 if (!(rc == CPIOERR_ENOENT)) return rc;
-                rc = expandRegular(fsm, psm, archive, nodigest);
+                rc = expandRegular(ts, fsm, psm, archive, nodigest);
             } else if (S_ISDIR(st->st_mode)) {
                /* Directories replacing something need early backup */
                 rc = fsmBackup(fsm);
@@ -1766,7 +1788,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfi
fi, FD_t cfd,
 
         if (!fsm->postpone) {
             rc = ((S_ISREG(st->st_mode) && st->st_nlink > 1)
-                  ? fsmCommitLinks(fsm) : fsmCommit(fsm, fsm->ix));
+                  ? fsmCommitLinks(ts, fsm) : fsmCommit(ts, fsm, fsm->ix));
         }
         if (rc) {
             break;
diff --git a/lib/package.c b/lib/package.c
index 6fb95a6..b63ba28 100644
--- a/lib/package.c
+++ b/lib/package.c
@@ -18,6 +18,9 @@
 #include "rpmio/rpmio_internal.h"      /* fd digest bits */
 #include "lib/header_internal.h"       /* XXX headerCheck */
 
+#include "lib/rpmplugins.h"             /* rpm plugins hooks */
+#include "lib/rpmts_internal.h"         /* rpm ts struct */
+
 #include "debug.h"
 
 static const unsigned int nkeyids_max = 256;
@@ -495,7 +498,7 @@ rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp,
char ** msg)
     return rc;
 }
 
-static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags, 
+static rpmRC rpmpkgRead(rpmts ts, rpmKeyring keyring, rpmVSFlags vsflags, 
                        FD_t fd, const char * fn, Header * hdrp)
 {
     pgpDigParams sig = NULL;
@@ -640,9 +643,14 @@ static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags
vsflags,
        break;
     }
 
+    /* run verify hook for all plugins */
+    if (rpmpluginsCallVerify(ts->plugins, keyring, &sigtd, sig) ==
RPMRC_FAIL) {
+       goto exit;  
+    }
+
     /** @todo Implement disable/enable/warn/error/anal policy. */
     rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, &msg);
-       
+
     switch (rc) {
     case RPMRC_OK:             /* Signature is OK. */
        rpmlog(RPMLOG_DEBUG, "%s: %s", fn, msg);
@@ -710,7 +718,7 @@ rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char *
fn, Header * hdrp)
     rpmVSFlags vsflags = rpmtsVSFlags(ts);
     rpmKeyring keyring = rpmtsGetKeyring(ts, 1);
 
-    rc = rpmpkgRead(keyring, vsflags, fd, fn, hdrp);
+    rc = rpmpkgRead(ts, keyring, vsflags, fd, fn, hdrp);
 
     rpmKeyringFree(keyring);
 
diff --git a/lib/psm.c b/lib/psm.c
index 8f5376d..dac3b0d 100644
--- a/lib/psm.c
+++ b/lib/psm.c
@@ -420,7 +420,7 @@ static rpmRC runScript(rpmpsm psm, ARGV_const_t
prefixes,
        sfd = rpmtsScriptFd(psm->ts);
 
     rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
-    rc = rpmScriptRun(script, arg1, arg2, sfd,
+    rc = rpmScriptRun(psm->ts, script, arg1, arg2, sfd,
                      prefixes, warn_only, selinux);
     rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
 
diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
index 9098aa5..daa53d9 100644
--- a/lib/rpmplugins.c
+++ b/lib/rpmplugins.c
@@ -110,6 +110,43 @@ rpmRC rpmpluginsAddCollectionPlugin(rpmPlugins plugins,
const char *name)
     return rc;
 }
 
+rpmRC rpmpluginsAddSecurityPlugin(rpmPlugins plugins, const char *name)
+{
+    char *path;
+    char *options;
+    int rc = RPMRC_FAIL;
+
+    path = rpmExpand("%{?__security_}",name, "}", NULL);
+    if (!path || rstreq(path, "")) {
+#ifdef ENFORCE_SECURITY
+       rpmlog(RPMLOG_ERR, _("Failed to expand %%__security_%s macro\n"),
name);
+#else
+       rpmlog(RPMLOG_INFO, _("Failed to expand %%__security_%s macro\n"),
name);
+#endif
+       goto exit;
+    }
+
+    /* split the options from the path */
+#define SKIPSPACE(s)    { while (*(s) &&  risspace(*(s))) (s)++; }
+#define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; }
+    options = path;
+    SKIPNONSPACE(options);
+    if (risspace(*options)) {
+       *options = '\0';
+       options++;
+       SKIPSPACE(options);
+    }
+    if (*options == '\0') {
+       options = NULL;
+    }
+
+    rc = rpmpluginsAdd(plugins, name, path, options);
+
+  exit:
+    _free(path);
+    return rc;
+}
+
 rpmPlugins rpmpluginsFree(rpmPlugins plugins)
 {
     int i;
@@ -195,3 +232,194 @@ rpmRC rpmpluginsCallCollectionPreRemove(rpmPlugins
plugins, const char *name)
     RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_COLL_PRE_REMOVE);
     return hookFunc();
 }
+
+rpmRC rpmpluginsCallTsmPre(rpmPlugins plugins, rpmts ts)
+{
+    rpmRC (*hookFunc)(rpmts);
+    int i;
+    rpmRC rc = RPMRC_OK;
+    const char *name = NULL;
+
+    for (i = 0; i < plugins->count; i++) {
+       name = plugins->names[i];
+       RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_TSM_PRE);
+       if ( hookFunc(ts) == RPMRC_FAIL )
+               rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallTsmPost(rpmPlugins plugins, rpmts ts)
+{
+    rpmRC (*hookFunc)(rpmts);
+    int i;
+    rpmRC rc = RPMRC_OK;
+    const char *name = NULL;
+
+    for (i = 0; i < plugins->count; i++) {
+       name = plugins->names[i];
+       RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_TSM_POST);
+       if ( hookFunc(ts) == RPMRC_FAIL )
+               rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallPsmPre(rpmPlugins plugins, rpmte te)
+{
+    rpmRC (*hookFunc)(rpmte);
+    int i;
+    rpmRC rc = RPMRC_OK;
+    const char *name = NULL;
+
+    for (i = 0; i < plugins->count; i++) {
+       name = plugins->names[i];
+       RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_PSM_PRE);
+       if ( hookFunc(te) == RPMRC_FAIL )
+               rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallPsmPost(rpmPlugins plugins, rpmte te)
+{
+    rpmRC (*hookFunc)(rpmte);
+    int i;
+    rpmRC rc = RPMRC_OK;
+    const char *name = NULL;
+
+    for (i = 0; i < plugins->count; i++) {
+       name = plugins->names[i];
+       RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_PSM_POST);
+       if ( hookFunc(te) == RPMRC_FAIL )
+               rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallVerify(rpmPlugins plugins, rpmKeyring keyring,
+                           rpmtd sigtd, pgpDigParams sig)
+{
+    rpmRC (*hookFunc)(rpmKeyring, rpmtd, pgpDigParams);
+    int i;
+    rpmRC rc = RPMRC_OK;
+    const char *name = NULL;
+
+    for (i = 0; i < plugins->count; i++) {
+       name = plugins->names[i];
+       RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_VERIFY);
+       if ( hookFunc(keyring, sigtd, sig) == RPMRC_FAIL )
+               rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallFileOpened(rpmPlugins plugins, const char* path)
+{
+    rpmRC (*hookFunc)(const char*);
+    int i;
+    rpmRC rc = RPMRC_OK;
+    const char *name = NULL;
+
+    for (i = 0; i < plugins->count; i++) {
+       name = plugins->names[i];
+       RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_FILE_OPENED);
+       if ( hookFunc(path) == RPMRC_FAIL )
+               rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallFileUpdated(rpmPlugins plugins, const char* path,
+                                char *buf, size_t len)
+{
+    rpmRC (*hookFunc)(const char*, char*, size_t);
+    int i;
+    rpmRC rc = RPMRC_OK;
+    const char *name = NULL;
+
+    for (i = 0; i < plugins->count; i++) {
+       name = plugins->names[i];
+       RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_FILE_UPDATED);
+       if ( hookFunc(path, buf, len) == RPMRC_FAIL )
+               rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallFileClosed(rpmPlugins plugins, const char* path)
+{
+    rpmRC (*hookFunc)(const char*);
+    int i;
+    rpmRC rc = RPMRC_OK;
+    const char *name = NULL;
+
+    for (i = 0; i < plugins->count; i++) {
+       name = plugins->names[i];
+       RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_FILE_CLOSED);
+       if ( hookFunc(path) == RPMRC_FAIL )
+               rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallDirCreated(rpmPlugins plugins, const char* path, mode_t
mode)
+{
+    rpmRC (*hookFunc)(const char*, mode_t);
+    int i;
+    rpmRC rc = RPMRC_OK;
+    const char *name = NULL;
+
+    for (i = 0; i < plugins->count; i++) {
+       name = plugins->names[i];
+       RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_DIR_CREATED);
+       if ( hookFunc(path, mode) == RPMRC_FAIL )
+               rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallFileConflict(rpmPlugins plugins, rpmts ts, rpmte te,
rpmfi fi,
+                                 rpmfi oldFi, Header oldHeader)
+{
+    rpmRC (*hookFunc)(rpmts, rpmte, rpmfi, rpmfi, Header);
+    int i;
+    rpmRC rc = RPMRC_OK;
+    const char *name = NULL;
+
+    for (i = 0; i < plugins->count; i++) {
+       name = plugins->names[i];
+       RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_FILE_CONFLICT);
+       if ( hookFunc(ts, te, fi, oldFi, oldHeader) == RPMRC_FAIL )
+               rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallScriptExec(rpmPlugins plugins, ARGV_const_t argv)
+{
+    rpmRC (*hookFunc)(ARGV_const_t);
+    int i;
+    rpmRC rc = RPMRC_OK;
+    const char *name = NULL;
+
+    for (i = 0; i < plugins->count; i++) {
+       name = plugins->names[i];
+       RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_SCRIPT_EXEC);
+       if ( hookFunc(argv) == RPMRC_FAIL )
+               rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h
index 7985559..c5434bb 100644
--- a/lib/rpmplugins.h
+++ b/lib/rpmplugins.h
@@ -11,11 +11,28 @@ extern "C" {
 
 #define PLUGINHOOK_INIT_FUNC                   pluginhook_init
 #define PLUGINHOOK_CLEANUP_FUNC                        pluginhook_cleanup
+
 #define PLUGINHOOK_OPENTE_FUNC                 pluginhook_opente
 #define PLUGINHOOK_COLL_POST_ADD_FUNC          pluginhook_coll_post_add
 #define PLUGINHOOK_COLL_POST_ANY_FUNC          pluginhook_coll_post_any
 #define PLUGINHOOK_COLL_PRE_REMOVE_FUNC
pluginhook_coll_pre_remove
 
+#define PLUGINHOOK_TSM_PRE_FUNC                        pluginhook_tsm_pre
+#define PLUGINHOOK_TSM_POST_FUNC               pluginhook_tsm_post
+
+#define PLUGINHOOK_PSM_PRE_FUNC                        pluginhook_psm_pre
+#define PLUGINHOOK_PSM_POST_FUNC               pluginhook_psm_post
+#define PLUGINHOOK_VERIFY_FUNC                 pluginhook_verify
+
+#define PLUGINHOOK_FILE_OPENED_FUNC            pluginhook_file_opened
+#define PLUGINHOOK_FILE_UPDATED_FUNC           pluginhook_file_updated
+#define PLUGINHOOK_FILE_CLOSED_FUNC            pluginhook_file_closed
+#define PLUGINHOOK_DIR_CREATED_FUNC            pluginhook_dir_created
+#define PLUGINHOOK_FILE_CONFLICT_FUNC          pluginhook_file_conflict
+
+#define PLUGINHOOK_SCRIPT_EXEC_FUNC            pluginhook_script_exec
+
+
 enum rpmPluginHook_e {
     PLUGINHOOK_NONE            = 0,
     PLUGINHOOK_INIT            = 1 << 0,
@@ -23,7 +40,18 @@ enum rpmPluginHook_e {
     PLUGINHOOK_OPENTE          = 1 << 2,
     PLUGINHOOK_COLL_POST_ADD   = 1 << 3,
     PLUGINHOOK_COLL_POST_ANY   = 1 << 4,
-    PLUGINHOOK_COLL_PRE_REMOVE = 1 << 5
+    PLUGINHOOK_COLL_PRE_REMOVE = 1 << 5,
+    PLUGINHOOK_TSM_PRE         = 1 << 6,
+    PLUGINHOOK_TSM_POST                = 1 << 7,
+    PLUGINHOOK_PSM_PRE         = 1 << 8,                       
+    PLUGINHOOK_PSM_POST                        = 1 << 9,               
+    PLUGINHOOK_VERIFY          = 1 << 10,              
+    PLUGINHOOK_FILE_OPENED     = 1 << 11,              
+    PLUGINHOOK_FILE_UPDATED    = 1 << 12,              
+    PLUGINHOOK_FILE_CLOSED     = 1 << 13,
+    PLUGINHOOK_DIR_CREATED     = 1 << 14,
+    PLUGINHOOK_FILE_CONFLICT   = 1 << 15,
+    PLUGINHOOK_SCRIPT_EXEC     = 1 << 16
 };
 
 typedef rpmFlags rpmPluginHook;
@@ -61,6 +89,14 @@ rpmRC rpmpluginsAdd(rpmPlugins plugins, const char *name,
const char *path, cons
 rpmRC rpmpluginsAddCollectionPlugin(rpmPlugins plugins, const char *name);
 
 /** \ingroup rpmplugins
+ * Add and open a security plugin
+ * @param plugins      plugins structure to add a security plugin to
+ * @param name         name of security plugin to open
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsAddSecurityPlugin(rpmPlugins plugins, const char *name);
+
+/** \ingroup rpmplugins
  * Determine if a plugin has been added already
  * @param plugins      plugins structure
  * @param name         name of plugin to check
@@ -119,6 +155,104 @@ rpmRC rpmpluginsCallCollectionPostAny(rpmPlugins
plugins, const char *name);
  */
 rpmRC rpmpluginsCallCollectionPreRemove(rpmPlugins plugins, const char
*name);
 
+/** \ingroup rpmplugins
+ * Call the pre transaction plugin hook
+ * @param plugins      plugins structure
+ * @param ts           processed transaction
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallTsmPre(rpmPlugins plugins, rpmts ts);
+
+/** \ingroup rpmplugins
+ * Call the post transaction plugin hook
+ * @param plugins      plugins structure
+ * @param ts           processed transaction
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallTsmPost(rpmPlugins plugins, rpmts ts);
+
+/** \ingroup rpmplugins
+ * Call the post transaction element plugin hook
+ * @param plugins      plugins structure
+ * @param te           processed transaction element
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallPsmPre(rpmPlugins plugins, rpmte te);
+
+/** \ingroup rpmplugins
+ * Call the post transaction element plugin hook
+ * @param plugins      plugins structure
+ * @param te           processed transaction element
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallPsmPost(rpmPlugins plugins, rpmte te);
+
+/** \ingroup rpmplugins
+ * Call the verify plugin hook
+ * @param plugins      plugins structure
+ * @param keyring      rpm keyring
+ * @param sigtd                rpm tag data
+ * @param sig          pgpDig parameters
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallVerify(rpmPlugins plugins, rpmKeyring keyring, rpmtd
sigtd, pgpDigParams sig);
+
+/** \ingroup rpmplugins
+ * Call the file opened plugin hook
+ * @param plugins      plugins structure
+ * @param path         filepath
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallFileOpened(rpmPlugins plugins, const char* path);
+
+/** \ingroup rpmplugins
+ * Call the file updated plugin hook
+ * @param plugins      plugins structure
+ * @param path         filepath
+ * @param buf          buffer with file chunk
+ * @param len          length of the buffer
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallFileUpdated(rpmPlugins plugins, const char* path, char
*buf, size_t len);
+
+/** \ingroup rpmplugins
+ * Call the file closed plugin hook
+ * @param plugins      plugins structure
+ * @param path         filepath
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallFileClosed(rpmPlugins plugins, const char* path);
+
+/** \ingroup rpmplugins
+ * Call the directory created plugin hook
+ * @param plugins      plugins structure
+ * @param path         filepath
+ * @param mode         file mode
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallDirCreated(rpmPlugins plugins, const char* path, mode_t
mode);
+
+/** \ingroup rpmplugins
+ * Call the file conflict plugin hook
+ * @param plugins      plugins structure
+ * @param ts           processed transaction
+ * @param te           processed transaction element
+ * @param fi           new conflicting file
+ * @param oldfi                previously installed file
+ * @param oldHeader    package header that provided the file previously
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallFileConflict(rpmPlugins plugins, rpmts ts, rpmte te,
+                                rpmfi fi, rpmfi oldFi, Header oldHeader);
+
+/** \ingroup rpmplugins
+ * Call the script execution plugin hook
+ * @param plugins      plugins structure
+ * @param argv         script arguments
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallScriptExec(rpmPlugins plugins, ARGV_const_t argv);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/rpmscript.c b/lib/rpmscript.c
index 57c24c6..3adde0d 100644
--- a/lib/rpmscript.c
+++ b/lib/rpmscript.c
@@ -14,6 +14,9 @@
 #include "rpmio/rpmlua.h"
 #include "lib/rpmscript.h"
 
+#include "lib/rpmplugins.h"     /* rpm plugins hooks */
+#include "lib/rpmts_internal.h" /* ts struct */
+
 #include "debug.h"
 
 struct rpmScript_s {
@@ -91,7 +94,7 @@ static rpmRC runLuaScript(int selinux, ARGV_const_t
prefixes,
 
 static const char * const SCRIPT_PATH =
"PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
 
-static void doScriptExec(int selinux, ARGV_const_t argv, ARGV_const_t
prefixes,
+static void doScriptExec(rpmts ts, int selinux, ARGV_const_t argv,
ARGV_const_t prefixes,
                        FD_t scriptFd, FD_t out)
 {
     int pipes[2];
@@ -169,7 +172,10 @@ static void doScriptExec(int selinux, ARGV_const_t
argv, ARGV_const_t prefixes,
        }
 
        if (xx == 0) {
-           xx = execv(argv[0], argv);
+                /* Run script exec hook for all plugins */
+                if (rpmpluginsCallScriptExec(ts->plugins, argv) !=
RPMRC_FAIL) {
+                       xx = execv(argv[0], argv);
+                }
        }
     }
     _exit(127); /* exit 127 for compatibility with bash(1) */
@@ -202,7 +208,7 @@ exit:
 /**
  * Run an external script.
  */
-static rpmRC runExtScript(int selinux, ARGV_const_t prefixes,
+static rpmRC runExtScript(rpmts ts, int selinux, ARGV_const_t prefixes,
                   const char *sname, rpmlogLvl lvl, FD_t scriptFd,
                   ARGV_t * argvp, const char *script, int arg1, int arg2)
 {
@@ -258,7 +264,7 @@ static rpmRC runExtScript(int selinux, ARGV_const_t
prefixes,
     } else if (pid == 0) {/* Child */
        rpmlog(RPMLOG_DEBUG, "%s: execv(%s) pid %d\n",
               sname, *argvp[0], (unsigned)getpid());
-       doScriptExec(selinux, *argvp, prefixes, scriptFd, out);
+       doScriptExec(ts, selinux, *argvp, prefixes, scriptFd, out);
     }
 
     do {
@@ -296,7 +302,7 @@ exit:
     return rc;
 }
 
-rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
+rpmRC rpmScriptRun(rpmts ts, rpmScript script, int arg1, int arg2, FD_t
scriptFd,
                   ARGV_const_t prefixes, int warn_only, int selinux)
 {
     ARGV_t args = NULL;
@@ -315,7 +321,7 @@ rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2,
FD_t scriptFd,
     if (rstreq(args[0], "<lua>")) {
        rc = runLuaScript(selinux, prefixes, script->descr, lvl, scriptFd,
&args, script->body, arg1, arg2);
     } else {
-       rc = runExtScript(selinux, prefixes, script->descr, lvl, scriptFd,
&args, script->body, arg1, arg2);
+       rc = runExtScript(ts, selinux, prefixes, script->descr, lvl,
scriptFd, &args, script->body, arg1, arg2);
     }
     argvFree(args);
 
diff --git a/lib/rpmscript.h b/lib/rpmscript.h
index 7d584bc..61f02a2 100644
--- a/lib/rpmscript.h
+++ b/lib/rpmscript.h
@@ -28,7 +28,7 @@ RPM_GNUC_INTERNAL
 rpmScript rpmScriptFree(rpmScript script);
 
 RPM_GNUC_INTERNAL
-rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
+rpmRC rpmScriptRun(rpmts ts, rpmScript script, int arg1, int arg2, FD_t
scriptFd,
                    ARGV_const_t prefixes, int warn_only, int selinux);
 
 RPM_GNUC_INTERNAL
diff --git a/lib/rpmte.c b/lib/rpmte.c
index 35b8e3e..4e98c32 100644
--- a/lib/rpmte.c
+++ b/lib/rpmte.c
@@ -941,7 +941,7 @@ int rpmteProcess(rpmte te, pkgGoal goal)
     int scriptstage = (goal != PKG_INSTALL && goal != PKG_ERASE);
     int test = (rpmtsFlags(te->ts) & RPMTRANS_FLAG_TEST);
     int reset_fi = (scriptstage == 0 && test == 0);
-    int failed = 1;
+    int failed = 0;
 
     /* Dont bother opening for elements without pre/posttrans scripts */
     if (goal == PKG_PRETRANS || goal == PKG_POSTTRANS) {
@@ -955,7 +955,17 @@ int rpmteProcess(rpmte te, pkgGoal goal)
     }
 
     if (rpmteOpen(te, reset_fi)) {
-       failed = rpmpsmRun(te->ts, te, goal);
+
+       /* Run pre transaction element hook for all plugins */
+       if (goal != PKG_PRETRANS && goal != PKG_POSTTRANS) {
+               failed = rpmpluginsCallPsmPre(rpmtsPlugins(te->ts), te);
+       }
+       if (!failed) {
+               failed = rpmpsmRun(te->ts, te, goal);
+               /* Run post transaction element hook for all plugins*/
+               if (goal != PKG_PRETRANS && goal != PKG_POSTTRANS)
+                       failed = rpmpluginsCallPsmPre(rpmtsPlugins(te->ts),
te);
+               }
        rpmteClose(te, reset_fi);
     }
     
diff --git a/lib/transaction.c b/lib/transaction.c
index c05d3af..56e840c 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -21,6 +21,8 @@
 #include "lib/rpmts_internal.h"
 #include "rpmio/rpmhook.h"
 
+#include "lib/rpmplugins.h"
+
 /* XXX FIXME: merge with existing (broken?) tests in system.h */
 /* portability fiddles */
 #if STATFS_IN_SYS_STATVFS
@@ -409,6 +411,9 @@ static void handleInstInstalledFile(const rpmts ts,
rpmte p, rpmfi fi, int fx,
        if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)
            rConflicts = 0;
 
+        /* run file conflict hook for all plugins */
+        rpmpluginsCallFileConflict(ts->plugins, ts, p, fi, otherFi,
otherHeader);
+
        if (rConflicts) {
            char *altNEVR = headerGetAsString(otherHeader, RPMTAG_NEVRA);
            char *fn = rpmfiFNIndex(fi, fx);
@@ -1414,6 +1419,34 @@ static int rpmtsProcess(rpmts ts)
     return rc;
 }
 
+static rpmRC rpmteSetupSecurityPlugins(rpmts ts)
+{
+    rpmRC rc = 0;
+    char *plugins = NULL, *plugin = NULL;
+    char delims[] = ",";
+
+    plugins = rpmExpand("%{?__security_plugins}", NULL);
+    if (!plugins || rstreq(plugins, "")) {
+#ifdef ENFORCE_SECURITY
+       rpmlog(RPMLOG_ERR, _("Failed to expand %%__security_plugins
macro\n"));
+#else
+       rpmlog(RPMLOG_INFO, _("Failed to expand %%__security_plugins
macro\n"));
+#endif
+       return -1;
+    }
+
+    plugin = strtok(plugins, delims);
+    while(plugin != NULL) {
+       rpmlog(RPMLOG_DEBUG, _("plugin is %s\n"), plugin);
+        if (!rpmpluginsPluginAdded(ts->plugins, (const char*)plugin)) {
+               rc = rpmpluginsAddSecurityPlugin(ts->plugins, (const
char*)plugin);
+        }
+        plugin = strtok(NULL, delims);
+    }
+    free(plugins);
+    return rc;
+}
+
 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
 {
     int rc = -1; /* assume failure */
@@ -1441,11 +1474,25 @@ int rpmtsRun(rpmts ts, rpmps okProbs,
rpmprobFilterFlags ignoreSet)
        goto exit;
     }
 
+
+    rc = rpmteSetupSecurityPlugins(ts);
+
+#ifdef ENFORCE_SECURITY
+    if (rc == -1) {
+       goto exit;
+    }
+#endif
+
     rpmtsSetupCollections(ts);
 
     /* Check package set for problems */
     tsprobs = checkProblems(ts);
 
+    /* Run pre transaction hook for all plugins */
+    if ( rpmpluginsCallTsmPre(ts->plugins, ts) == RPMRC_FAIL) {
+       goto exit;
+    }
+
     /* Run pre-transaction scripts, but only if there are no known
      * problems up to this point and not disabled otherwise. */
     if (!((rpmtsFlags(ts) &
(RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_NOPRE))
@@ -1489,6 +1536,11 @@ int rpmtsRun(rpmts ts, rpmps okProbs,
rpmprobFilterFlags ignoreSet)
        runTransScripts(ts, PKG_POSTTRANS);
     }
 
+    /* Run post transaction hook for all plugins */
+    if ( rpmpluginsCallTsmPost(ts->plugins, ts) == RPMRC_FAIL) {
+       goto exit;
+    }
+
 exit:
     /* Finish up... */
     (void) umask(oldmask);
diff --git a/macros.in b/macros.in
index f55dcbe..b8e7f3c 100644
--- a/macros.in
+++ b/macros.in
@@ -1031,6 +1031,13 @@ done \
 %__collection_sepolicy_flags   1
 
 
#---------------------------------------------------------------------------
---
+# Security specific macros
+%__security_plugins     sample
+%__plugindir           %{_libdir}/rpm-plugins
+%__security_sample     %{__plugindir}/sec-sample-plugin.so
+
+
+#--------------------------------------------------------------------------
----
 # Macros for further automated spec %setup and patch application
 
 # default to plain patch
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 69230de..b15417f 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -13,7 +13,7 @@ AM_LDFLAGS = -avoid-version -module -shared
 
 pluginsdir = $(libdir)/rpm-plugins
 
-plugins_LTLIBRARIES = exec.la sepolicy.la
+plugins_LTLIBRARIES = exec.la sepolicy.la sec-sample-plugin.la
 
 exec_la_SOURCES = plugin.h exec.c
 exec_la_LIBADD = $(top_builddir)/lib/librpm.la
$(top_builddir)/rpmio/librpmio.la
@@ -21,3 +21,6 @@ exec_la_LIBADD = $(top_builddir)/lib/librpm.la
$(top_builddir)/rpmio/librpmio.la
 sepolicy_la_SOURCES = plugin.h sepolicy.c
 sepolicy_la_LIBADD = $(top_builddir)/lib/librpm.la
$(top_builddir)/rpmio/librpmio.la @WITH_SELINUX_LIB@ @WITH_SEMANAGE_LIB@
 
+secsampleplugin_la_SOURCES = plugin.h sec-sample-plugin.c
+secsampleplugin_la_LIBADD = $(top_builddir)/lib/librpm.la
$(top_builddir)/rpmio/librpmio.la
+
diff --git a/plugins/plugin.h b/plugins/plugin.h
index 5156f93..9aedd19 100644
--- a/plugins/plugin.h
+++ b/plugins/plugin.h
@@ -7,9 +7,31 @@
 #include "lib/rpmplugins.h"
 #include "lib/rpmchroot.h"
 
+/* general plugin hooks */
 rpmRC PLUGINHOOK_INIT_FUNC(rpmts ts, const char * name, const char * opts);
 rpmRC PLUGINHOOK_CLEANUP_FUNC(void);
+
+/* collection plugin hooks */
 rpmRC PLUGINHOOK_OPENTE_FUNC(rpmte te);
 rpmRC PLUGINHOOK_COLL_POST_ANY_FUNC(void);
 rpmRC PLUGINHOOK_COLL_POST_ADD_FUNC(void);
 rpmRC PLUGINHOOK_COLL_PRE_REMOVE_FUNC(void);
+
+/* per transaction plugin hooks */
+rpmRC PLUGINHOOK_TSM_PRE_FUNC(rpmts ts);
+rpmRC PLUGINHOOK_TSM_POST_FUNC(rpmts ts);
+
+/* per transaction element plugin hooks */
+rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te);
+rpmRC PLUGINHOOK_PSM_POST_FUNC(rpmte te);
+rpmRC PLUGINHOOK_VERIFY_FUNC(rpmKeyring keyring, rpmtd sigtd, pgpDig sig);
+
+/* per file plugin hooks */
+rpmRC PLUGINHOOK_FILE_OPENED_FUNC(const char* path); 
+rpmRC PLUGINHOOK_FILE_UPDATED_FUNC(const char* path, char *buf, size_t
len);
+rpmRC PLUGINHOOK_FILE_CLOSED_FUNC(const char* path);
+rpmRC PLUGINHOOK_DIR_CREATED_FUNC(const char* path, mode_t mode);
+rpmRC PLUGINHOOK_FILE_CONFLICT_FUNC(rpmts ts, rpmte te, rpmfi fi, rpmfi
oldFi, Header oldHeader);
+
+/*per script plugin hooks */
+rpmRC PLUGINHOOK_SCRIPT_EXEC_FUNC(ARGV_const_t argv);
diff --git a/plugins/sec-sample-plugin.c b/plugins/sec-sample-plugin.c
new file mode 100644
index 0000000..bc59225
--- /dev/null
+++ b/plugins/sec-sample-plugin.c
@@ -0,0 +1,82 @@
+#include "plugin.h"
+
+rpmPluginHook PLUGIN_HOOKS = \
+       PLUGINHOOK_INIT | \
+       PLUGINHOOK_CLEANUP | \
+        PLUGINHOOK_TSM_PRE | \
+        PLUGINHOOK_TSM_POST | \
+        PLUGINHOOK_PSM_PRE | \                 
+        PLUGINHOOK_PSM_POST | \                
+        PLUGINHOOK_VERIFY | \          
+        PLUGINHOOK_FILE_OPENED | \     
+        PLUGINHOOK_FILE_UPDATED | \
+        PLUGINHOOK_FILE_CLOSED | \
+        PLUGINHOOK_DIR_CREATED | \
+        PLUGINHOOK_FILE_CONFLICT | \
+        PLUGINHOOK_SCRIPT_EXEC;
+
+rpmRC PLUGINHOOK_INIT_FUNC(rpmts ts, const char *name, const char *opts)
+{
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_CLEANUP_FUNC(void)
+{
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_TSM_PRE_FUNC(rpmts ts)
+{
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_TSM_POST_FUNC(rpmts ts)
+{
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te)
+{
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_PSM_POST_FUNC(rpmte te)
+{
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_VERIFY_FUNC(rpmKeyring keyring, rpmtd sigtd, pgpDig sig)
+{
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_FILE_OPENED_FUNC(const char* path)
+{
+    return RPMRC_OK;
+}
+ 
+rpmRC PLUGINHOOK_FILE_UPDATED_FUNC(const char* path, char *buf, size_t len)
+{
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_FILE_CLOSED_FUNC(const char* path)
+{
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_DIR_CREATED_FUNC(const char* path, mode_t mode)
+{
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_FILE_CONFLICT_FUNC(rpmts ts, rpmte te, rpmfi fi, rpmfi
oldFi, Header oldHeader)
+{
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_SCRIPT_EXEC_FUNC(ARGV_const_t argv)
+{
+    return RPMRC_OK;
+}
+
-- 
1.7.9.5

Attachment: smime.p7s
Description: S/MIME cryptographic signature

_______________________________________________
Rpm-maint mailing list
Rpm-maint@lists.rpm.org
http://lists.rpm.org/mailman/listinfo/rpm-maint

Reply via email to