Adding security msm plugin
authorElena Reshetova <elena.reshetova@intel.com>
Fri, 4 Jan 2013 10:46:42 +0000 (12:46 +0200)
committerAnas Nashif <anas.nashif@intel.com>
Sun, 3 Feb 2013 00:44:45 +0000 (16:44 -0800)
16 files changed:
configure.ac
lib/fsm.c
lib/package.c
lib/rpmplugins.c
lib/rpmplugins.h
lib/transaction.c
macros.in
packaging/rpm.spec
plugins/Makefile.am
plugins/msm-plugin.c [new file with mode: 0644]
plugins/msm.h [new file with mode: 0644]
plugins/msmconfig.c [new file with mode: 0644]
plugins/msmmanifest.c [new file with mode: 0644]
plugins/msmmatch.c [new file with mode: 0644]
plugins/msmxattr.c [new file with mode: 0644]
plugins/plugin.h

index 7a8a3085eef4afff6ccf497cf3548350ee196f45..e5a11e7cc2d5eb7a7b618682d5463d0e3011f7b6 100644 (file)
@@ -665,6 +665,61 @@ AC_SUBST(WITH_SELINUX_LIB)
 AC_SUBST(WITH_SEMANAGE_LIB)
 AM_CONDITIONAL(SELINUX,[test "$with_selinux" = yes])
 
+
+WITH_MSM_LIB=
+AC_ARG_WITH(msm, [AS_HELP_STRING([--with-msm],[build with msm support])],
+[case "$with_msm" in
+yes|no) ;;
+*) AC_MSG_ERROR([invalid argument to --with-msm])
+  ;;
+esac],
+[with_msm=no])
+
+AS_IF([test "$with_msm" = yes],[
+    save_LIBS="$LIBS"
+    AC_CHECK_LIB([xml2],[xmlReaderForMemory],[],[
+      AC_MSG_ERROR([--with-msm given, but xmlReaderForMemory not found in libxml2])])
+    LIBS="$save_LIBS"
+  AC_CHECK_HEADER([sys/capability.h],[
+    save_LIBS="$LIBS"
+    AC_CHECK_LIB([cap],[cap_set_file],[],[
+      AC_MSG_ERROR([--with-msm given, but cap_set_file not found in libcap])])
+    LIBS="$save_LIBS"
+  ],[
+    AC_MSG_ERROR([--with-msm given, but sys/capability.h not found])
+  ])
+  AC_CHECK_HEADER([attr/xattr.h],[
+    save_LIBS="$LIBS"
+    AC_CHECK_LIB([attr],[setxattr],[],[
+      AC_MSG_ERROR([--with-msm given, but setxattr not found in libattr])])
+    LIBS="$save_LIBS"
+  ],[
+    AC_MSG_ERROR([--with-msm given, but attr/xattr.h not found])
+  ])
+  AC_CHECK_HEADER([uthash.h],[
+    save_LIBS="$LIBS"
+    LIBS="$save_LIBS"
+  ],[
+    AC_MSG_ERROR([--with-msm given, but uthash.h not found])
+  ])
+  AC_CHECK_HEADER([sys/smack.h],[
+     save_LIBS="$LIBS"
+    LIBS="$save_LIBS"
+   ],[
+     AC_MSG_ERROR([--with-msm given, but smack.h not found])
+   ])
+])
+
+AS_IF([test "$with_msm" = yes],[
+  AC_DEFINE(WITH_MSM, 1, [Build with msm support?])
+  WITH_MSM_LIB="`xml2-config --libs` -lcap -lattr -lsmack -lmagic"
+  WITH_MSM_INCLUDE="`xml2-config --cflags`"
+])
+AC_SUBST(WITH_MSM_LIB)
+AC_SUBST(WITH_MSM_INCLUDE)
+AM_CONDITIONAL(MSM,[test "$with_msm" = yes])
+
+
 # libcap
 WITH_CAP_LIB=
 AC_ARG_WITH(cap, [AS_HELP_STRING([--with-cap],[build with capability support])],
index 5ebf28d4d7b03fa9e2b9803cc94574f17fb04355..ab4e18034eaf1aa233cfa1296293623054bdabed 100644 (file)
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -23,6 +23,7 @@
 #include "lib/rpmfi_internal.h"        /* XXX fi->apath, ... */
 #include "lib/rpmte_internal.h"        /* XXX rpmfs */
 #include "lib/rpmts_internal.h"        /* rpmtsSELabelFoo() only */
+#include "lib/rpmplugins.h"     /* rpm plugins hooks */
 #include "lib/rpmug.h"
 #include "lib/cpio.h"
 
@@ -108,6 +109,7 @@ struct fsm_s {
     const char * dirName;      /*!< File directory name. */
     const char * baseName;     /*!< File base name. */
     struct selabel_handle *sehandle;   /*!< SELinux label handle (if any). */
+    rpmPlugins plugins;        /*!< Rpm plugins handle */
 
     unsigned fflags;           /*!< File flags. */
     rpmFileAction action;      /*!< File disposition. */
@@ -1151,9 +1153,10 @@ static int fsmMknod(const char *path, mode_t mode, dev_t dev)
  * Create (if necessary) directories not explicitly included in package.
  * @param dnli         file state machine data
  * @param sehandle     selinux label handle (bah)
+ * @param plugins      rpm plugins handle
  * @return             0 on success
  */
-static int fsmMkdirs(rpmfi fi, rpmfs fs, struct selabel_handle *sehandle)
+static int fsmMkdirs(rpmfi fi, rpmfs fs, struct selabel_handle *sehandle, rpmPlugins plugins)
 {
     DNLI_t dnli = dnlInitIterator(fi, fs, 0);
     struct stat sb;
@@ -1221,6 +1224,10 @@ static int fsmMkdirs(rpmfi fi, rpmfs fs, struct selabel_handle *sehandle)
                            "%s directory created with perms %04o\n",
                            dn, (unsigned)(mode & 07777));
                }
+               if (!rc) {
+                   /* Run file closed hook for all plugins */
+                    rc = rpmpluginsCallFsmCommit(plugins, dn, mode, DIR_TYPE_UNOWNED);
+               }
                *te = '/';
            }
            if (rc)
@@ -1551,6 +1558,10 @@ static int fsmCommit(FSM_t fsm, int ix)
         if (!rc && !getuid()) {
             rc = fsmSetSELabel(fsm->sehandle, fsm->path, fsm->sb.st_mode);
         }
+        /* Call fsm commit hook for all plugins */
+        if (!rc) {
+            rc = rpmpluginsCallFsmCommit(fsm->plugins, fsm->path, fsm->sb.st_mode, DIR_TYPE_NORMAL);
+        }
         if (S_ISLNK(st->st_mode)) {
             if (!rc && !getuid())
                 rc = fsmLChown(fsm->path, fsm->sb.st_uid, fsm->sb.st_gid);
@@ -1640,12 +1651,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfi fi, FD_t cfd,
        rc = CPIOERR_INTERNAL;
 
     fsm->sehandle = rpmtsSELabelHandle(ts);
+    fsm->plugins = rpmtsPlugins(ts);
+        
     /* transaction id used for temporary path suffix while installing */
     rasprintf(&fsm->suffix, ";%08x", (unsigned)rpmtsGetTid(ts));
 
     /* Detect and create directories not explicitly in package. */
     if (!rc) {
-       rc = fsmMkdirs(fi, rpmteGetFileStates(te), fsm->sehandle);
+       rc = fsmMkdirs(fi, rpmteGetFileStates(te), fsm->sehandle, fsm->plugins);
     }
 
     while (!rc) {
@@ -1684,6 +1697,15 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfi fi, FD_t cfd,
             break;
         }
 
+       /* Run fsm init hook for all plugins */
+        rc = rpmpluginsCallFsmInit(fsm->plugins, fsm->path, fsm->sb.st_mode);
+        
+        /* Exit on error. */
+        if (rc) {
+            fsm->postpone = 1;
+            break;
+        }
+       
        if (S_ISREG(fsm->sb.st_mode) && fsm->sb.st_nlink > 1)
            fsm->postpone = saveHardLink(fsm, &li);
 
index b6bea09c781a8fb216ace82b7e288c47b441b154..157c969007d575a8895ce7e53810a645b5e4d62c 100644 (file)
@@ -18,6 +18,8 @@
 #include "rpmio/rpmio_internal.h"      /* fd digest bits */
 #include "lib/header_internal.h"       /* XXX headerCheck */
 
+#include "lib/rpmplugins.h"     /* rpm plugins hooks */
+
 #include "debug.h"
 
 static const unsigned int nkeyids_max = 256;
@@ -495,7 +497,7 @@ rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg)
     return rc;
 }
 
-static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags, 
+static rpmRC rpmpkgRead(rpmPlugins plugins, rpmKeyring keyring, rpmVSFlags vsflags, 
                        FD_t fd, const char * fn, Header * hdrp)
 {
     pgpDigParams sig = NULL;
@@ -646,6 +648,9 @@ static rpmRC rpmpkgRead(rpmKeyring keyring, rpmVSFlags vsflags,
 
     /** @todo Implement disable/enable/warn/error/anal policy. */
     rc = rpmVerifySignature(keyring, &sigtd, sig, ctx, &msg);
+    
+    /* Run verify hook for all plugins */
+    rc = rpmpluginsCallVerify(plugins, keyring, &sigtd, sig, ctx, rc);
        
     switch (rc) {
     case RPMRC_OK:             /* Signature is OK. */
@@ -714,7 +719,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(rpmtsPlugins(ts), keyring, vsflags, fd, fn, hdrp);
 
     rpmKeyringFree(keyring);
 
index d5ab09a9dd84232a1f7815fc919852c46d59b049..2d4fb01cd3df6f1b991d55961203c8e5bdcd1b93 100644 (file)
@@ -314,3 +314,75 @@ rpmRC rpmpluginsCallScriptletPost(rpmPlugins plugins, const char *s_name, int ty
 
     return rc;
 }
+
+rpmRC rpmpluginsCallVerify(rpmPlugins plugins, rpmKeyring keyring, rpmtd sigtd, 
+                           pgpDigParams sig, DIGEST_CTX ctx, int res)
+{
+    rpmRC (*hookFunc)(rpmKeyring, rpmtd, pgpDigParams, DIGEST_CTX, int);
+    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, ctx, res) == RPMRC_FAIL)
+           rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallFsmInit(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_FSM_INIT);
+        if (hookFunc(path, mode) == RPMRC_FAIL)
+            rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallFsmCommit(rpmPlugins plugins, const char* path,
+                                mode_t mode, int type)
+{
+    rpmRC (*hookFunc)(const char*, mode_t, int);
+    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_FSM_COMMIT);
+        if (hookFunc(path, mode, type) == RPMRC_FAIL)
+            rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
+
+rpmRC rpmpluginsCallFileConflict(rpmPlugins plugins, rpmts ts, char* path,
+                               Header oldHeader, rpmfi oldFi, int res)
+{
+    rpmRC (*hookFunc)(rpmts, char*, Header, rpmfi, int);
+    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, path, oldHeader, oldFi, res) == RPMRC_FAIL)
+            rc = RPMRC_FAIL;
+    }
+
+    return rc;
+}
index cff3e6cc1569c6a24c17ba686f83c00faa52a8c6..8e35d81ab7b763650ac95f74588d44b83ee1b451 100644 (file)
@@ -22,11 +22,16 @@ extern "C" {
 
 #define PLUGINHOOK_PSM_PRE_FUNC        pluginhook_psm_pre
 #define PLUGINHOOK_PSM_POST_FUNC        pluginhook_psm_post
+#define PLUGINHOOK_VERIFY_FUNC    pluginhook_verify
 
 #define PLUGINHOOK_SCRIPTLET_PRE_FUNC    pluginhook_scriptlet_pre
 #define PLUGINHOOK_SCRIPTLET_FORK_POST_FUNC    pluginhook_scriptlet_fork_post
 #define PLUGINHOOK_SCRIPTLET_POST_FUNC    pluginhook_scriptlet_post
 
+#define PLUGINHOOK_FSM_INIT_FUNC        pluginhook_fsm_init
+#define PLUGINHOOK_FSM_COMMIT_FUNC        pluginhook_fsm_commit
+#define PLUGINHOOK_FILE_CONFLICT    pluginhook_file_conflict
+
 enum rpmPluginHook_e {
     PLUGINHOOK_NONE            = 0,
     PLUGINHOOK_INIT            = 1 << 0,
@@ -41,9 +46,21 @@ enum rpmPluginHook_e {
     PLUGINHOOK_PSM_POST        = 1 << 9,
     PLUGINHOOK_SCRIPTLET_PRE    = 1 << 10,
     PLUGINHOOK_SCRIPTLET_FORK_POST    = 1 << 11,
-    PLUGINHOOK_SCRIPTLET_POST    = 1 << 12
+    PLUGINHOOK_SCRIPTLET_POST    = 1 << 12,
+    PLUGINHOOK_VERIFY    = 1 << 13,
+    PLUGINHOOK_FSM_INIT    = 1 << 14,
+    PLUGINHOOK_FSM_COMMIT    = 1 << 15,
+    PLUGINHOOK_FILE_CONFLICT    = 1 << 16
+    
 };
 
+/* indicates if a directory is part of rpm package or created by rpm itself */
+typedef enum rpmPluginDirType_e {
+    DIR_TYPE_NONE    = 0,
+    DIR_TYPE_NORMAL    = 1 << 0, 
+    DIR_TYPE_UNOWNED    = 1 << 1
+} rpmPluginDirType;
+
 /* indicates the way the scriptlet is executed */
 typedef enum rpmScriptletExecutionFlow_e {
     RPMSCRIPTLET_NONE    = 0,
@@ -207,6 +224,49 @@ rpmRC rpmpluginsCallScriptletForkPost(rpmPlugins plugins, const char *path, int
  */
 rpmRC rpmpluginsCallScriptletPost(rpmPlugins plugins, const char *s_name, int type, int res);
 
+/** \ingroup rpmplugins
+ * Call the verify hook
+ * @param plugins      plugins structure
+ * @param keyring      RPM keyring
+ * @param sigtd                signature tag
+ * @param sig          OpenPGP signature parameters
+ * @param res          scriptlet execution result code
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallVerify(rpmPlugins plugins, rpmKeyring keyring, rpmtd sigtd, 
+                           pgpDigParams sig, DIGEST_CTX ctx, int res);
+
+/** \ingroup rpmplugins
+ * Call the fsm init hook
+ * @param plugins      plugins structure
+ * @param path         file full path
+ * @param mode         file mode
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallFsmInit(rpmPlugins plugins, const char* path, mode_t mode);
+                           
+/** \ingroup rpmplugins
+ * Call the fsm commit hook
+ * @param plugins      plugins structure
+ * @param path         file full path
+ * @param mode         file mode
+ * @param type         file type
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallFsmCommit(rpmPlugins plugins, const char* path, mode_t mode, int type);
+
+/** \ingroup rpmplugins
+ * Call the fsm commit hook
+ * @param plugins      plugins structure
+ * @param ts           transaction set
+ * @param path         new file path
+ * @param oldHeader    old header
+ * @param oldFi                old file
+ * @param res           return code
+ * @return             RPMRC_OK on success, RPMRC_FAIL otherwise
+ */
+rpmRC rpmpluginsCallFileConflict(rpmPlugins plugins, rpmts ts, char* path, Header oldHeader, rpmfi oldFi, int res);
+
 #ifdef __cplusplus
 }
 #endif
index 3a7cb740cd47a2da3537aed7cb50f7b2582caac3..659a08656a4b952af27dbbd3a095010184bea91b 100644 (file)
@@ -421,9 +421,16 @@ static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfi fi, int fx,
                rState = RPMFILE_STATE_WRONGCOLOR;
        }
 
+       if (rConflicts) {
+               char *path = rpmfiFNIndex(fi, fx);
+               /* Call file conflict hook for all plugins */
+               rpmpluginsCallFileConflict(ts->plugins, ts, path, otherHeader, otherFi, rConflicts);
+       }
+       
        /* Somebody used The Force, lets shut up... */
-       if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)
+       if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES) {
            rConflicts = 0;
+       }
 
        if (rConflicts) {
            char *altNEVR = headerGetAsString(otherHeader, RPMTAG_NEVRA);
index 12d6c29e19d9d76efa18b9d1204cda67d148bb47..1e89aeefab1a70e9ab240f93b7c86191b7791045 100644 (file)
--- a/macros.in
+++ b/macros.in
@@ -1077,6 +1077,12 @@ PreReq: python >= %minver, python < %maxver
 %__collection_sepolicy         %{__plugindir}/sepolicy.so
 %__collection_sepolicy_flags   1
 
+#------------------------------------------------------------------------------
+# transaction specific macros
+%__transaction_plugins     msm
+%__plugindir           %{_libdir}/rpm-plugins
+%__transaction_msm       %{__plugindir}/msm.so
+
 #------------------------------------------------------------------------------
 # Macros for further automated spec %setup and patch application
 
index ee3d049a8019f9154646cfd7131c24cd0a86d185..7f56c8eee2e64d6839292d96f02d72fad5efc960 100644 (file)
@@ -22,12 +22,11 @@ BuildRequires:  pkgconfig(popt)
 BuildRequires:  xz-devel
 BuildRequires:  pkgconfig(zlib)
 BuildRequires:  pkgconfig(nss)
-%if 0%{?enable_security}
 BuildRequires:  uthash-devel
 BuildRequires:  libxml2-devel
 BuildRequires:  libattr-devel
-BuildRequires:  libsmack-devel
-%endif
+BuildRequires:  pkgconfig(libsmack)
+
 
 Provides:       rpminst
 Provides:      rpm-libs
@@ -93,10 +92,8 @@ and requires some packages that are usually required
 Summary: MSM security plugin for rpm
 Group: Development/Libraries
 Requires: rpm = %{version}-%{release}
-Requires: libsmack
+Requires: smack
 Requires: libxml2
-Requires: file
-Requires: uthash
 Requires: nss
 
 %description security-plugin
@@ -141,7 +138,7 @@ BUILDTARGET="--build=%{_target_cpu}-tizen-linux"
 autoreconf -i -f
 ./configure --disable-dependency-tracking --prefix=%{_prefix} --mandir=%{_mandir} --infodir=%{_infodir} \
 --libdir=%{_libdir} --sysconfdir=/etc --localstatedir=/var  --with-lua \
---with-acl --with-cap  --enable-shared %{?with_python: --enable-python} $BUILDTARGET
+--with-acl --with-cap  --enable-shared %{?with_python: --enable-python} --with-msm $BUILDTARGET
 
 make %{?_smp_mflags}
 
@@ -160,9 +157,7 @@ mkdir -p %{buildroot}%{_sysconfdir}/rpm
 cp -a tizen_macros %{buildroot}/usr/lib/rpm
 mkdir -p %{buildroot}/usr/lib/rpm/tizen
 install -m 755 %{SOURCE13} %{buildroot}/usr/lib/rpm/tizen
-%if 0%{?enable_security}
 install -m 644 %{SOURCE22} ${RPM_BUILD_ROOT}%{_sysconfdir}/device-sec-policy
-%endif
 ln -s ../tizen_macros %{buildroot}/usr/lib/rpm/tizen/macros
 for d in BUILD RPMS SOURCES SPECS SRPMS BUILDROOT ; do
   mkdir -p %{buildroot}/usr/src/packages/$d
@@ -291,9 +286,9 @@ rm -f var/lib/rpm/Filemd5s var/lib/rpm/Filedigests var/lib/rpm/Requireversion va
         %{_libdir}/librpmio.so
         %{_libdir}/librpmsign.so
         %{_libdir}/pkgconfig/rpm.pc
-%if 0%{?enable_security}
+
 %files security-plugin
 %defattr(-,root,root)
 %{_libdir}/rpm-plugins/msm.so
 %config(noreplace) %{_sysconfdir}/device-sec-policy
-%endif
+
index a9c962cb783eeed152d6e2feed0d7ce436f32313..5fd7662f1fefe57f072d7698d7edbc3da631cb84 100644 (file)
@@ -24,3 +24,10 @@ sepolicy_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmi
 
 plugins_LTLIBRARIES += sepolicy.la
 endif
+
+if MSM
+msm_la_SOURCES = plugin.h msm.h msm-plugin.c msmconfig.c msmmatch.c msmxattr.c msmmanifest.c
+msm_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la @WITH_MSM_LIB@
+
+plugins_LTLIBRARIES += msm.la
+endif
diff --git a/plugins/msm-plugin.c b/plugins/msm-plugin.c
new file mode 100644 (file)
index 0000000..b62ab8a
--- /dev/null
@@ -0,0 +1,855 @@
+/*
+ * This file is part of MSM security plugin
+ * Greatly based on the code of MSSF security plugin
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Tero Aho <ext-tero.aho@nokia.com>
+ *
+ * Copyright (C) 2011 -2013 Intel Corporation.
+ *
+ * Contact: Elena Reshetova <elena.reshetova@intel.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; either version 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include "plugin.h"
+#include "debug.h"
+
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#include <sys/stat.h>
+
+#include <rpm/rpmfileutil.h>
+#include <rpm/rpmmacro.h>
+#include <rpm/rpmpgp.h>
+#include <rpm/rpmkeyring.h>
+#include <rpm/rpmdb.h>
+
+#include "rpmio/rpmbase64.h"
+#include "rpmio/rpmlog.h"
+
+#include "msm.h"
+
+/*hooks that are used in msm plugin */
+
+rpmPluginHook PLUGIN_HOOKS = \
+       PLUGINHOOK_INIT | \
+       PLUGINHOOK_CLEANUP | \
+        PLUGINHOOK_TSM_PRE | \
+        PLUGINHOOK_TSM_POST | \
+        PLUGINHOOK_PSM_PRE | \
+        PLUGINHOOK_PSM_POST | \
+        PLUGINHOOK_FSM_COMMIT | \
+        PLUGINHOOK_FSM_INIT | \
+        PLUGINHOOK_FILE_CONFLICT | \
+        PLUGINHOOK_VERIFY;
+
+
+typedef struct fileconflict {
+    const char *path;
+    const char *pkg_name;
+    sw_source_x *sw_source;
+    UT_hash_handle hh;
+} fileconflict;
+
+typedef struct packagecontext {
+    char *data;                                        /*!< base64 manifest data */
+    manifest_x *mfx;                           /*!< parsed manifest data */
+    rpmte te;                                  /*!< related te */
+    struct packagecontext *next;               /*!< next in linked list */
+    struct smack_accesses *smack_accesses;     /*!<  handle to smack_accesses */
+} packagecontext;
+
+static rpmts ts = NULL;
+static int rootSWSource= 0;
+static manifest_x *root = NULL; /* pointer to device security policy file */
+static packagecontext *context = NULL;
+static sw_source_x *current = NULL;
+static packagecontext *contextsHead = NULL;
+static packagecontext *contextsTail = NULL;
+static fileconflict *allfileconflicts = NULL;
+static char* ownSmackLabel = NULL;
+static int SmackEnabled = 0;
+static magic_t cookie = NULL;
+static int package_created = 0;
+
+rpmRC PLUGINHOOK_INIT_FUNC(rpmts _ts, const char *name, const char *opts)
+{
+    ts = _ts;
+    int res = 0;
+
+    rpmlog(RPMLOG_INFO, "reading device security policy from %s\n", DEVICE_SECURITY_POLICY);
+    root = msmProcessDevSecPolicyXml(DEVICE_SECURITY_POLICY);
+
+    if (root) {
+           if (msmSetupSWSources(NULL, root, NULL)) {
+               rpmlog(RPMLOG_ERR, "Failed to setup device security policy from %s\n", 
+                      DEVICE_SECURITY_POLICY);
+               return RPMRC_FAIL;
+           }
+    } else {
+           /* Do not allow plug-in to proceed without security policy existing */
+           rpmlog(RPMLOG_ERR, "Failed to process sw sources from %s\n", 
+                  DEVICE_SECURITY_POLICY);
+               return RPMRC_FAIL;
+    }
+
+    /* check its own security context and store it for the case when packages without manifest will be installed */
+    struct stat buf;
+
+    if (stat(SMACK_LOAD_PATH, &buf) == 0) {
+        res = smack_new_label_from_self(&ownSmackLabel);
+        SmackEnabled = 1;
+        if (res != 0) {
+            rpmlog(RPMLOG_ERR, "Failed to obtain rpm security context\n");
+            return RPMRC_FAIL;
+        }
+    } else {
+        rpmlog(RPMLOG_INFO, "Smack disabled in kernel. Going to the image build mode. \n");
+        ownSmackLabel = strdup("_");
+        SmackEnabled = 0;
+    }
+
+    if (stat(SMACK_RULES_PATH, &buf) != 0) {
+        rpmlog(RPMLOG_INFO, "A directory for writing smack rules is missing. Creating one.\n");
+        mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH; // 644 -rwer--r--
+        if (stat(SMACK_RULES_PATH_BEG, &buf) != 0) {
+               if (mkdir(SMACK_RULES_PATH_BEG, mode) != 0) {
+                       rpmlog(RPMLOG_ERR, "Failed to create a sub-directory for smack rules\n");
+                       return RPMRC_FAIL;
+               }    
+        }
+        if (mkdir(SMACK_RULES_PATH, mode) != 0){
+            rpmlog(RPMLOG_ERR, "Failed to create a directory for smack rules\n");
+            return RPMRC_FAIL;
+        } 
+    }
+
+    rpmlog(RPMLOG_DEBUG, "rpm security context: %s\n", ownSmackLabel);
+
+    cookie = magic_open(0); 
+    if (!cookie)
+       return RPMRC_FAIL; 
+
+    if (magic_load(cookie, NULL) != 0) {
+       rpmlog(RPMLOG_ERR, "cannot load magic database - %s\n", magic_error(cookie));   
+       magic_close(cookie);
+       return RPMRC_FAIL;
+    }
+    
+    return RPMRC_OK;
+}
+
+static int findSWSourceByName(sw_source_x *sw_source, void *param, void* param2)
+{
+    const char *name = (const char *)param;
+    return strcmp(sw_source->name, name); 
+}
+
+rpmRC PLUGINHOOK_FILE_CONFLICT_FUNC(rpmts ts, char* path,
+                                     Header oldHeader, rpmfi oldFi, 
+                                     int rpmrc)
+{
+    fileconflict *fc;
+    if (!path)
+       return rpmrc; 
+    rpmlog(RPMLOG_DEBUG, "FILE_CONFLICT_FUNC hook  path %s\n",path);
+
+    const char *name = headerGetString(oldHeader, RPMTAG_SECSWSOURCE);    
+    if (!name || !root) {
+           return rpmrc; /* no sw source(s) - abnormal state */
+    }
+    const char *pkg_name = headerGetString(oldHeader, RPMTAG_NAME);
+
+    sw_source_x *sw_source = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)name, NULL);
+    if (!sw_source)
+           return rpmrc; /* no old sw_source - abnormal state */
+
+    HASH_FIND(hh, allfileconflicts, path, strlen(path), fc);
+    if (!fc) {
+           /* Add new file conflict into hash */
+           fc = xcalloc(1, sizeof(*fc));
+           if (!fc) return RPMRC_FAIL;
+           fc->path = path;
+           fc->sw_source = sw_source;
+           fc->pkg_name = pkg_name;
+           HASH_ADD_KEYPTR(hh, allfileconflicts, path, strlen(path), fc);
+    } else {
+           /* Many packages have installed the same file */
+           if (strcmp(sw_source->rankkey, fc->sw_source->rankkey) <= 0) {
+               /* Change sw source to the higher ranked one */
+               fc->sw_source = sw_source;
+           }
+           msmFreePointer((void**)&path);
+    }
+    
+    if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES) {
+       /* Conflict has been noted, now return ok. It will be actually */
+       /* resolved later when conflicting package signature is verified */
+       /* and sw_source is known. */
+           return rpmrc;
+    }
+    return rpmrc;
+}
+
+rpmRC PLUGINHOOK_TSM_PRE_FUNC(rpmts ts)
+{
+    return RPMRC_OK;
+}
+
+static int findSWSourceBySignature(sw_source_x *sw_source, void *param, void* param2)
+{
+    origin_x *origin;
+    keyinfo_x *keyinfo;
+    pgpDigParams sig = (pgpDigParams)param;
+    DIGEST_CTX ctx = (DIGEST_CTX)param2;
+    pgpDigParams key = NULL;
+    int res = 0;
+    
+    for (origin = sw_source->origins; origin; origin = origin->prev) {
+           for (keyinfo = origin->keyinfos; keyinfo; keyinfo = keyinfo->prev) {
+               if (pgpPrtParams(keyinfo->keydata, keyinfo->keylen, PGPTAG_PUBLIC_KEY, &key)) {
+                       rpmlog(RPMLOG_INFO, "invalid sw source key\n");
+                       return -1;
+               }
+               if (pgpVerifySignature(key, sig, ctx) == RPMRC_OK) {
+                       return 0;
+               }
+           }
+    }
+    return 1;
+}
+
+rpmRC PLUGINHOOK_VERIFY_FUNC(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig, DIGEST_CTX ctx, int rpmrc)
+{
+    current = NULL;
+
+#if 0 
+    if (!root) {
+       if (rpmrc == RPMRC_NOKEY) {
+           rpmlog(RPMLOG_INFO, "package verified as root sw source\n");
+           rootSWSource = 1; /* accept any signed package as root */
+           return RPMRC_OK;
+       }
+       rpmlog(RPMLOG_ERR, "No device security policy, cannot verify signature\n");
+       return rpmrc;
+    } 
+
+
+// make currently that even non-signed package with root policy will be treated as trusted
+
+   if (!root) {
+           rpmlog(RPMLOG_INFO, "package verified as root sw source\n");
+           rootSWSource = 1; /* accept any signed package as root */
+           return RPMRC_OK;
+   } 
+
+//------------------
+#endif
+
+   if (!root) {
+           rpmlog(RPMLOG_INFO, "No device policy found\n");
+           rootSWSource = 1; /* accept any signed package as root */
+           return rpmrc;
+   } 
+
+    if (rpmrc == RPMRC_NOKEY) {
+           /* No key, revert to unknown sw source. */
+           rpmlog(RPMLOG_INFO, "no key for signature, cannot search sw source\n");
+           goto exit;
+    }
+    if (rpmrc) {
+           /* RPM failed to verify signature */
+           rpmlog(RPMLOG_ERR, "Invalid signature, cannot search sw source\n");
+           return rpmrc;
+    }
+    if (sigtd->tag != RPMSIGTAG_RSA) {
+           /* Not RSA, revert to unknown sw source. */
+           rpmlog(RPMLOG_INFO, "no RSA signature, cannot search sw source\n");
+           goto exit;
+    }
+    current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceBySignature, sig, ctx);
+    if (current)
+           rpmlog(RPMLOG_INFO, "signature matches sw source %s\n", current->name);
+    else
+           rpmlog(RPMLOG_INFO, "valid signature but no matching sw source\n");
+
+ exit:
+    if (!current) {
+           current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)"_default_", NULL);
+           if (current)
+               rpmlog(RPMLOG_INFO, "using _default_ sw source\n");
+        else { // for now in case default sw source isn't there yet, allow to think that it is coming from root
+               current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)"root", NULL);
+                   if (current)
+                       rpmlog(RPMLOG_INFO, "using _root_ sw source now for testing\n");
+           }
+    }
+
+    return rpmrc;
+}
+
+static packagecontext *msmNew(rpmte te)
+{
+    Header h;
+    struct rpmtd_s msm;
+    int count;
+    packagecontext *ctx = NULL;
+    const char *sw_source = NULL;
+
+    rpmtdReset(&msm);
+    
+    h = rpmteHeader(te);
+    if (!h) return NULL;
+    
+    ctx = xcalloc(1, sizeof(*ctx));
+    if (!ctx) {
+           goto exit1;
+    }
+    ctx->te = te;
+
+    if (!headerIsEntry(h, RPMTAG_SECMANIFEST)) {
+           goto exit1;
+    }
+
+    if (!headerGet(h, RPMTAG_SECMANIFEST, &msm, HEADERGET_MINMEM)) {
+           goto exit1;
+    }
+
+    count = rpmtdCount(&msm);
+    if (count != 1) {
+           goto exit2;
+    }
+
+    ctx->data = xstrdup(rpmtdNextString(&msm));
+    rpmlog(RPMLOG_INFO, "%s manifest b64 data: %.40s...\n", 
+          rpmteN(ctx->te), ctx->data);
+  
+ exit2:
+    rpmtdFreeData(&msm);
+ exit1:
+    if (rpmteType(ctx->te) == TR_ADDED) {
+           /* Save sw_source name into database, we need it when package */
+           /* is removed because signature verify is not called then. */
+           if (current) sw_source = current->name;
+           else if (rootSWSource) sw_source = rpmteN(ctx->te);
+           
+           if (!sw_source || !headerPutString(h, RPMTAG_SECSWSOURCE, sw_source)) {
+               rpmlog(RPMLOG_ERR, "Failed to save sw source for %s, sw_source: %s\n", 
+                      rpmteN(ctx->te), sw_source);
+               msmFreePointer((void**)&ctx->data);
+               msmFreePointer((void**)&ctx);
+           }
+    }
+    headerFree(h);
+
+    return ctx;
+}
+
+static packagecontext *msmAddTE(rpmte te)
+{
+    packagecontext *ctx = msmNew(te);
+    if (ctx) {
+       /* add the new policy to the list */
+           if (!contextsHead) {
+               contextsHead = ctx;
+               contextsTail = ctx;
+           } else {
+               if (rpmteType(te) == TR_ADDED) {
+                       /* add to the end of the list */
+                       contextsTail->next = ctx;
+                       contextsTail = ctx;
+               } else {
+                       /* add to the beginning of the list */
+                       ctx->next = contextsHead;
+                       contextsHead = ctx;
+               }
+           }
+    }
+    return ctx;
+}
+
+rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te)
+{
+    packagecontext *ctx = NULL;
+    manifest_x *mfx = NULL;
+    char *xml = NULL;
+    size_t xmllen;
+    rpmRC rc = RPMRC_OK;
+    int ret = 0;
+
+    if (!root && !rootSWSource) {
+       /* no sw source config, just exit */
+       goto exit;
+    }
+
+    if (!current) {
+        /* this means that verify hook has not been called */
+        current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)"_default_", NULL);
+           if (current)
+               rpmlog(RPMLOG_INFO, "using _default_ sw source\n");
+        else { 
+            rpmlog(RPMLOG_ERR, "Default source isn't availiable. Package source can't be determined. Abort installation\n");
+               goto fail;
+           }
+    }
+
+    ctx = msmAddTE(te);
+    if (!ctx) {
+           rpmlog(RPMLOG_ERR, "Failed to create security context for %s\n",
+              rpmteNEVRA(te));
+           goto fail;
+    }
+
+    if (rpmteType(ctx->te) == TR_REMOVED) {
+
+           /* Verify hook is not called before remove, */
+           /* so get the sw_source name from package header */
+           Header h = rpmteHeader(te);
+           if (h) {
+               const char *name = headerGetString(h, RPMTAG_SECSWSOURCE);
+               if (name) { 
+                   current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)name, NULL);
+                   rpmlog(RPMLOG_INFO, "removing %s from sw source %s\n",
+                      rpmteN(ctx->te), name);
+               }
+               headerFree(h);
+           }
+           /* if (!current) {
+               rpmlog(RPMLOG_INFO, "no sw source for removing %s\n", rpmteN(ctx->te));
+               goto exit;
+           }*/
+    }
+
+    if (!ctx->data) {
+       rpmlog(RPMLOG_INFO, "No manifest in this package. Creating default one\n");
+
+        /* create default manifest manually. Make the package to belong to the domain where rpm is running */
+
+        mfx = calloc(1, sizeof(manifest_x));
+       if (!mfx)  goto fail;
+        mfx->sw_source = current;
+       mfx->name = strdup(rpmteN(ctx->te));
+        mfx->request = calloc(1, sizeof(request_x));
+       if (!mfx->request) {
+               msmFreePointer((void**)&mfx->name);
+               msmFreePointer((void**)&mfx);
+               goto fail;
+        }
+        mfx->request->ac_domain = strdup(ownSmackLabel);
+        rpmlog(RPMLOG_DEBUG, "Done with manifest creation\n");
+       
+    } else {
+        if (rpmBase64Decode(ctx->data, (void **) &xml, &xmllen) != 0) {
+               rpmlog(RPMLOG_ERR, "Failed to decode manifest for %s\n",
+                   rpmteN(ctx->te));
+               goto fail;
+        }
+
+        rpmlog(RPMLOG_INFO, "parsing %s manifest: \n%s", rpmteN(ctx->te), xml);
+        mfx = msmProcessManifestXml(xml, xmllen, current, rpmteN(ctx->te));
+
+        if (!mfx) {
+               rpmlog(RPMLOG_ERR, "Failed to parse manifest for %s\n",
+               rpmteN(ctx->te));
+               goto fail;
+        }
+    }
+
+
+    ctx->mfx = mfx;
+
+    int res = smack_accesses_new(&(ctx->smack_accesses)); 
+    if (res != 0) {
+           rpmlog(RPMLOG_ERR, "Failed to create smack access set\n");
+           goto fail;
+    }
+
+    if (rpmteType(ctx->te) == TR_ADDED) {
+
+       rpmlog(RPMLOG_DEBUG, "Installing the package\n");
+
+       package_x *package = NULL;
+
+       if (rootSWSource) {
+               /* this is the first package */
+               package = msmCreatePackage(mfx->name, mfx->sw_sources, 
+                                           mfx->provides, NULL);
+       } else if (mfx->sw_source) {
+               /* all packages must have sw_source */
+               package = msmCreatePackage(mfx->name, mfx->sw_source, 
+                                           mfx->provides, NULL);
+       } else {
+               rpmlog(RPMLOG_ERR, "Package doesn't have a sw source. Abnormal situation. Abort.\n");
+               goto fail;
+        }
+
+       if (!package) {
+                rpmlog(RPMLOG_ERR, "Package could not be created. \n");
+                goto fail; 
+       }
+           
+       mfx->provides = NULL; /* owned by package now */
+
+       if (!package->sw_source) { /* this must never happen */
+               rpmlog(RPMLOG_ERR, "Install failed. Check that configuration has at least root sw source installed.\n");
+               msmFreePackage(package);
+               package = NULL;
+               goto fail;
+       }
+           
+       rpmlog(RPMLOG_INFO, "adding %s manifest data to system, package_name %s\n", 
+                  rpmteN(ctx->te), package->name);
+
+       if (msmSetupPackages(ctx->smack_accesses, package, package->sw_source)) {
+               rpmlog(RPMLOG_ERR, "Package setup failed for %s\n", rpmteN(ctx->te) );
+               msmFreePackage(package);
+               package = NULL;
+               goto fail;
+       }
+
+       if (rootSWSource) {
+               /* current is root */
+               root = ctx->mfx;
+       } 
+
+        rpmlog(RPMLOG_DEBUG, "Starting the security setup...\n");
+        unsigned int smackLabel = 0;
+
+       if (rootSWSource || ctx->mfx->sw_source) {
+               if (ctx->mfx->sw_sources) {
+                               smackLabel = 1; /* setting this one on since this manifest doesn't have any define/request section */
+                       ret = msmSetupSWSources(ctx->smack_accesses, ctx->mfx, ts);
+                       if (ret) {
+                           rpmlog(RPMLOG_ERR, "SW source setup failed for %s\n",
+                                  rpmteN(ctx->te));
+                            msmCancelPackage(ctx->mfx->name);
+                           goto fail;
+                       }
+               }           
+               if (ctx->mfx->define) {
+                               if (ctx->mfx->define->name)
+                               smackLabel = 1;
+                               ret = msmSetupDefine(ctx->smack_accesses, ctx->mfx);
+                               if (ret) {
+                                       rpmlog(RPMLOG_ERR, "AC domain setup failed for %s\n",
+                                               rpmteN(ctx->te));
+                                       msmCancelPackage(ctx->mfx->name);
+                                       goto fail;
+                               }
+                       }           
+               if (ctx->mfx->request) {        
+                               if (ctx->mfx->request->ac_domain)
+                               smackLabel = 1;
+                               ret = msmSetupRequests(ctx->mfx);
+                               if (ret) {
+                                       rpmlog(RPMLOG_ERR, "Request setup failed for %s\n",
+                                               rpmteN(ctx->te));
+                                       msmCancelPackage(ctx->mfx->name);
+                                       goto fail;
+                               }
+                       }
+               if (ctx->smack_accesses) {
+                       ret = msmSetupSmackRules(ctx->smack_accesses, ctx->mfx->name, 0, SmackEnabled);
+                       smack_accesses_free(ctx->smack_accesses);
+                       ctx->smack_accesses = NULL;
+                               if (ret) {
+                               rpmlog(RPMLOG_ERR, "Setting up smack rules for %s failed\n",
+                                       rpmteN(ctx->te));
+                               msmCancelPackage(ctx->mfx->name);
+                               goto fail; 
+                       }
+              }
+              if (package->provides) {
+                       ret = msmSetupDBusPolicies(package);
+                       if (ret) {
+                           rpmlog(RPMLOG_ERR, "Setting up dbus policies for %s failed\n",
+                                  rpmteN(ctx->te));
+                           msmCancelPackage(ctx->mfx->name);
+                           goto fail;
+                       }
+               }
+       
+               /* last check is needed in order to catch in advance 
+               the situation when no ac domain defined or requested */
+               if (smackLabel == 0) {
+                       rpmlog(RPMLOG_ERR, "No ac domain defined or requested for package %s. Abort.\n",   rpmteN(ctx->te));
+                       msmCancelPackage(ctx->mfx->name);
+                       goto fail;
+               }
+       }
+
+
+       } else if (rpmteDependsOn(ctx->te)) { /* TR_REMOVED */
+               rpmlog(RPMLOG_INFO, "upgrading package %s by %s\n",
+                       rpmteNEVR(ctx->te), rpmteNEVR(rpmteDependsOn(ctx->te)));
+       } else if (mfx->sw_sources) {
+               rpmlog(RPMLOG_ERR, "Cannot remove sw source package %s\n",
+                       rpmteN(ctx->te));
+               goto fail;
+       }
+
+       rpmlog(RPMLOG_DEBUG, "Finished with pre psm hook \n");
+       package_created = 1;
+
+       goto exit;
+
+ fail: /* error, cancel the rpm operation */
+       rc = RPMRC_FAIL;
+
+ exit: /* success, continue rpm operation */
+       context = ctx;
+       msmFreePointer((void**)&xml);
+
+       return rc;
+}
+
+rpmRC PLUGINHOOK_FSM_INIT_FUNC(const char* path, mode_t mode)
+{
+
+    //check if there any conflicts that prevent file being written to the disk
+
+    fileconflict *fc;
+    packagecontext *ctx = context;
+    char * cleanedPath = NULL, *dupPath = NULL;
+    
+    rpmlog(RPMLOG_DEBUG, "Started with FSM_INIT_FUNC hook for file: %s\n", path);
+    
+    if (!ctx) return RPMRC_FAIL; 
+    if (!path) return RPMRC_FAIL; 
+           
+    dupPath = strdup(path);
+    cleanedPath = strchr(dupPath, ';');
+    if (cleanedPath)
+       *cleanedPath = '\0';
+       
+    //rpmlog(RPMLOG_DEBUG, "dupapth: %s\n", dupPath);
+    
+    HASH_FIND(hh, allfileconflicts, dupPath, strlen(dupPath), fc);
+    msmFreePointer((void**)&dupPath);
+
+    if (fc) {
+        //rpmlog(RPMLOG_DEBUG, "rpmteN(ctx->te) %s fc->pkg_name: %s\n", rpmteN(ctx->te), fc->pkg_name);
+       /* There is a conflict, see if we are not allowed to overwrite */
+           if ((!current || (strcmp(current->rankkey, fc->sw_source->rankkey) >= 0)) && (strcmp(rpmteN(ctx->te), fc->pkg_name))){
+               rpmlog(RPMLOG_ERR, "%s has file conflict in %s from sw source %s\n",
+                      rpmteN(ctx->te), fc->path, fc->sw_source->name);
+               return RPMRC_FAIL;
+           }
+           rpmlog(RPMLOG_INFO, "%s from %s overwrites %s from %s\n",
+                  rpmteN(ctx->te), current->name, fc->path, fc->sw_source->name);
+    }
+
+    rpmlog(RPMLOG_DEBUG, "Finished with FSM_INIT_FUNC hook for file: %s\n", path);
+    
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_FSM_COMMIT_FUNC(const char* path, mode_t mode, int type)
+{
+    packagecontext *ctx = context;
+    if (!ctx) return RPMRC_FAIL;
+    if (!path) return RPMRC_FAIL;
+
+    /* the type is ignored for now */
+    
+    rpmlog(RPMLOG_DEBUG, "Started with FSM_COMMIT_FUNC hook for file: %s\n", path);
+
+    if (ctx->mfx) {
+       file_x *file = xcalloc(1, sizeof(*file));
+       if (file) {
+               file->path = strndup(path, strlen(path) + 1);
+               LISTADD(ctx->mfx->files, file);
+               if (rpmteType(ctx->te) == TR_ADDED) {
+                       if (msmSetFileXAttributes(ctx->mfx, file->path, cookie) < 0) {
+                               rpmlog(RPMLOG_ERR, "Setting of extended attributes failed for file %s from package %s\n",
+                                               file->path, rpmteN(ctx->te));
+                               return RPMRC_FAIL;
+                       }
+               } 
+
+       } else
+               return RPMRC_FAIL;
+    } else {
+               rpmlog(RPMLOG_ERR, "Manifest is missing while it should be present for the package %s\n",
+                          rpmteN(ctx->te));
+               return RPMRC_FAIL;
+    }
+
+    rpmlog(RPMLOG_DEBUG, "Finished with FSM_COMMIT_FUNC hook for file: %s\n", path);
+    return RPMRC_OK;
+}
+
+rpmRC PLUGINHOOK_PSM_POST_FUNC(rpmte te, int rpmrc)
+{
+
+    int ret = 0;
+    packagecontext *ctx = context;
+    if (!ctx) return RPMRC_FAIL;
+    
+    if (!package_created) {
+       /* failure in rpm pre psm hook, rollback */
+       return RPMRC_FAIL;
+    }
+    
+    if (rpmrc) {
+       /* failure in rpm psm, rollback */
+       if (rpmteType(ctx->te) == TR_ADDED)
+           msmCancelPackage(ctx->mfx->name);
+           goto exit;
+    }
+
+    if (!ctx->mfx){
+        rpmlog(RPMLOG_ERR, "Manifest is missing while it should be present for the package %s\n",
+                          rpmteN(ctx->te));
+               goto exit;
+    }
+
+    if (rootSWSource) {
+           /* current is root */
+           root = context->mfx;
+    } 
+
+
+    if (rpmteType(ctx->te) == TR_REMOVED) {
+           if (ctx->mfx->sw_source) {
+               if (rpmteDependsOn(ctx->te)) {
+                       rpmlog(RPMLOG_INFO, "upgrading %s manifest data\n", 
+                          rpmteN(ctx->te));
+               } else {
+                       rpmlog(RPMLOG_INFO, "removing %s manifest data\n", 
+                          rpmteN(ctx->te));
+                   if (ctx->mfx->define || ctx->mfx->provides || ctx->mfx->sw_sources) {
+                           msmRemoveRules(ctx->smack_accesses, ctx->mfx, SmackEnabled);
+                   }       
+                   msmRemoveConfig(ctx->mfx);
+               }
+           }
+
+   }
+
+ exit:
+    current = NULL;
+
+    if (ret) {
+           return RPMRC_FAIL;
+    }
+    return rpmrc;
+}
+
+rpmRC PLUGINHOOK_TSM_POST_FUNC(rpmts ts, int rpmrc)
+{
+    packagecontext *ctx = context;
+    if (!ctx) return RPMRC_FAIL;
+    return RPMRC_OK;
+}
+
+static packagecontext *msmFree(packagecontext *ctx)
+{
+
+    while (ctx) {
+           packagecontext *next = ctx->next;
+           msmFreePointer((void**)&ctx->data);
+           ctx->mfx = msmFreeManifestXml(ctx->mfx);
+           if (ctx->smack_accesses) smack_accesses_free(ctx->smack_accesses);
+           msmFreePointer((void**)&ctx);
+           ctx = next;
+    }
+
+    return NULL;
+
+}
+
+rpmRC PLUGINHOOK_CLEANUP_FUNC(void)
+{
+
+    msmFreeInternalHashes(); // free hash structures first
+
+    if (root) {
+           msmSaveDeviceSecPolicyXml(root);
+           if (!rootSWSource)  root = msmFreeManifestXml(root);
+    }
+
+    ts = NULL;
+
+    contextsHead = contextsTail = msmFree(contextsHead);
+    contextsHead = contextsTail = NULL;
+
+    if (allfileconflicts) {
+           fileconflict *fc, *temp;
+           HASH_ITER(hh, allfileconflicts, fc, temp) {
+               HASH_DELETE(hh, allfileconflicts, fc);
+               msmFreePointer((void**)&fc->path);
+               msmFreePointer((void**)&fc);
+           }
+    }
+
+    msmFreePointer((void**)&ownSmackLabel);
+    if (cookie) magic_close(cookie);
+
+    return RPMRC_OK;
+}
+
+const char *msmQueryPackageFile(const char *rfor, 
+                                const char **dname, const char **pname)
+{
+    int match = 0;
+    const char *path = NULL;
+
+    if (ts) {
+           char *sep = strchr(rfor, ':');
+           if (sep && sep[1] == ':' && sep[2] == '/') 
+               path = &sep[2];
+           if (!path) return NULL;
+
+           rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, path, 0);
+           if (!mi)
+               mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, path, 0);
+           if (mi) {
+               Header h;
+               const char *name, *sw_source;
+               while ((h = rpmdbNextIterator(mi))) {
+                       rpmdbCheckSignals();
+                       name = headerGetString(h, RPMTAG_NAME);
+                       sw_source = headerGetString(h, RPMTAG_SECSWSOURCE);
+                       if (name && sw_source) {
+                           match = !strncmp(rfor, name, path - rfor - 2);
+                           rpmlog(RPMLOG_INFO, "file %s belongs to package %s in sw source %s %s\n", path, name, sw_source, (match ? "(matched request)" : ""));
+                           if (match) {
+                                   *pname = xstrdup(name);
+                                   *dname = xstrdup(sw_source);
+                                   break;
+                           }
+                       }
+               }
+               mi = rpmdbFreeIterator(mi);
+           }
+    }
+    return match ? path : NULL;
+}
+
+void msmFreePointer(void** ptr)
+{
+       if (*ptr)
+               free(*ptr);
+       *ptr = NULL;
+       return;
+}
diff --git a/plugins/msm.h b/plugins/msm.h
new file mode 100644 (file)
index 0000000..3a6e75c
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * This file is part of MSM security plugin
+ * Greatly based on the code of MSSF security plugin
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Tero Aho <ext-tero.aho@nokia.com>
+ *
+ * Copyright (C) 2011 - 2013 Intel Corporation.
+ *
+ * Contact: Elena Reshetova <elena.reshetova@intel.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; either version 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef MSM_H
+#define MSM_H
+
+#define IMA "security.ima"
+#define SMACK64TRANSMUTE "security.SMACK64TRANSMUTE"
+#define SMACK64 "security.SMACK64"
+#define SMACK64EXEC "security.SMACK64EXEC"
+
+#define SMACK_RULES_PATH "/etc/smack/accesses.d/"
+#define SMACK_RULES_PATH_BEG "/etc/smack/"
+#define DEVICE_SECURITY_POLICY "/etc/device-sec-policy"
+#define SMACK_LOAD_PATH "/smack/load"
+
+#define SMACK_ISOLATED_LABEL "Isolated"
+
+#define SMACK_LABEL_LENGTH 255
+#define SMACK_ACCESS_TYPE_LENGHT 5
+#define SMACK_UNINSTALL 1 
+#define RANK_LIMIT 10000
+
+#define DBUS_SERVICE   1
+#define DBUS_PATH      2
+#define DBUS_INTERFACE 3
+#define DBUS_METHOD    4
+#define DBUS_SIGNAL    5
+
+#include <uthash.h>
+#include <sys/capability.h>
+#include <sys/smack.h>
+#include <magic.h>
+#include "rpmio/rpmio.h"
+
+/** \ingroup msm
+ * List definitions.
+ * All lists are doubly-linked, the last element is stored to list pointer,
+ * which means that lists must be looped using the prev pointer, or by
+ * calling LISTHEAD first to go to start in order to use the next pointer.
+ */
+#define LISTADD(list, node)                    \
+    do {                                       \
+       (node)->prev = (list);                  \
+       if (list) (node)->next = (list)->next;  \
+       else (node)->next = NULL;               \
+       if (list) (list)->next = (node);        \
+       (list) = (node);                        \
+    } while (0);
+
+#define NODEADD(node1, node2)                                  \
+    do {                                                       \
+       (node2)->prev = (node1);                                \
+       (node2)->next = (node1)->next;                          \
+       if ((node1)->next) (node1)->next->prev = (node2);       \
+       (node1)->next = (node2);                                \
+    } while (0);
+
+#define LISTCAT(list, first, last)             \
+    if ((first) && (last)) {                   \
+       (first)->prev = (list);                 \
+       (list) = (last);                        \
+    }
+
+#define LISTDEL(list, node)                                    \
+    do {                                                       \
+       if ((node)->prev) (node)->prev->next = (node)->next;    \
+       if ((node)->next) (node)->next->prev = (node)->prev;    \
+       if (!((node)->prev) && !((node)->next)) (list) = NULL;  \
+    } while (0);
+
+#define LISTHEAD(list, node)                                   \
+    for ((node) = (list); (node)->prev; (node) = (node)->prev);        
+    
+#define LISTTAIL(list, node)                                   \
+    for ((node) = (list); (node)->next; (node) = (node)->next);
+
+/** \ingroup msm
+ * Structure definitions.
+ * These structures represent the parsed security manifest of a package.
+ */
+
+
+typedef struct file_x {
+    const char *path; /* file path */
+    ino_t ino; /* file inode */
+    struct file_x *prev;
+    struct file_x *next;
+} file_x;
+
+typedef struct filesystem_x {
+    const char *path; /* filesystem object absolute path */
+    const char *label; /* SMACK64 xattr */
+    const char *exec_label; /* SMACK64EXEC xattr */
+    const char *type; /* can be set as TRANSMUTABLE for directory */
+    struct filesystem_x *prev;
+    struct filesystem_x *next;
+ } filesystem_x;
+
+typedef struct ac_domain_x { /* structure for storing ac domain */
+    const char *name; /* ac domain name */
+    const char *match;
+    const char *type; /* ac domain policy type: "shared" or "restricted" or "NULL" (private) */
+    const char *plist; /* list of packages that allowed to request domain, if policy is "restricted" */
+    const char *pkg_name; /* package that defined ac domain */
+    struct ac_domain_x *prev;
+    struct ac_domain_x *next;
+    struct sw_source_x *sw_source; /* sw source of the package that defined the domain */
+    const char *origin;
+    UT_hash_handle hh;
+    int allowed;
+    struct ac_domain_x *older; /* previous version in upgrades */
+    struct ac_domain_x *newer; /* the newer upgraded version */
+} ac_domain_x;
+
+typedef struct annotation_x {
+    const char *name;
+    const char *value;
+} annotation_x;
+
+typedef struct member_x {
+    int type;
+    const char *name;
+    struct annotation_x *annotation;
+    struct member_x *prev;
+    struct member_x *next;
+} member_x;
+
+typedef struct interface_x {
+    const char *name;
+    struct annotation_x *annotation;
+    struct member_x *members;
+    struct interface_x *prev;
+    struct interface_x *next;
+} interface_x;
+
+typedef struct node_x {
+    const char *name;
+    struct annotation_x *annotation;
+    struct member_x *members;
+    struct interface_x *interfaces;
+    struct node_x *prev;
+    struct node_x *next;
+} node_x;
+
+typedef struct dbus_x {
+    const char *name;
+    const char *own;
+    const char *bus;
+    struct annotation_x *annotation;
+    struct node_x *nodes;
+    struct dbus_x *prev;
+    struct dbus_x *next;
+} dbus_x;
+
+typedef struct provide_x {
+    const char *name; /* _system_ or NULL */
+    struct ac_domain_x *ac_domains;
+    struct filesystem_x *filesystems;
+    struct dbus_x *dbuss;
+    const char *origin;
+    struct provide_x *prev;
+    struct provide_x *next;
+} provide_x;
+
+typedef struct request_x {
+    const char *ac_domain;
+} request_x;
+typedef struct keyinfo_x {
+    const unsigned char *keydata;
+    size_t keylen;
+    struct keyinfo_x *prev;
+    struct keyinfo_x *next;
+} keyinfo_x;
+
+typedef struct access_x {
+    const char *data;
+    const char *type;
+    struct access_x *prev;
+    struct access_x *next;
+} access_x;
+
+typedef struct origin_x {
+    const char *type;
+    struct keyinfo_x *keyinfos;
+    struct access_x *accesses;
+    struct origin_x *prev;
+    struct origin_x *next;
+} origin_x;
+
+typedef struct constraint_x {
+    const char *name;
+    const char *value;
+    struct constraint_x *prev;
+    struct constraint_x *next;
+} constraint_x;
+
+typedef struct d_request_x {
+    const char *label_name;
+    const char *ac_type;
+    struct d_request_x *prev;
+    struct d_request_x *next;
+} d_request_x;
+
+typedef struct d_permit_x {
+    const char *label_name;
+    const char *to_label_name;
+    const char *ac_type;
+    struct d_permit_x *prev;
+    struct d_permit_x *next;
+} d_permit_x;
+
+typedef struct d_provide_x {
+    const char *label_name;    
+    struct d_provide_x *prev;
+    struct d_provide_x *next;
+} d_provide_x;
+
+typedef struct define_x {
+    const char *name; /* ac domain name */
+    const char *policy; 
+    const char *plist; /* list of packages that are allowed to request the ac domain */
+    struct d_request_x *d_requests;
+    struct d_permit_x *d_permits;
+    struct d_provide_x *d_provides;
+} define_x;
+
+typedef struct package_x {
+    const char *name; /* package name */
+    struct sw_source_x *sw_source; /* package sw source */
+    struct provide_x *provides;
+    const char *modified; /* internal packages */
+    struct package_x *prev;
+    struct package_x *next;
+    UT_hash_handle hh;
+    struct package_x *older; /* previous version in upgrades */
+    struct package_x *newer; /* the newer upgraded version */
+} package_x;
+
+typedef struct sw_source_x {
+    const char *name;
+    const char *rankkey;
+    struct package_x *packages; /* config processing */
+    struct ac_domain_x *allowmatches; /* list of allow wildcards */
+    struct ac_domain_x *allows; /* hash of allowed ac domains */
+    struct ac_domain_x *denymatches; /* list of deny wildcards */
+    struct ac_domain_x *denys; /* hash of denied ac domains */
+    struct origin_x *origins;
+    struct sw_source_x *prev;
+    struct sw_source_x *next;
+    struct sw_source_x *parent;
+    struct sw_source_x *older; /* previous version in upgrades */
+    struct sw_source_x *newer; /* the newer upgraded version */
+} sw_source_x;
+
+typedef struct manifest_x { /*package manifest */
+    struct sw_source_x *sw_source; /* package sw source */
+    const char *name; /* package name */
+    struct provide_x *provides; /* assign section */
+    struct request_x *request; /* request section */
+    struct sw_source_x *sw_sources; /*defined software sources(non-NULL only for configuration manifests)*/
+    struct define_x *define; /* define section */
+    struct file_x *files; /* installed files */
+} manifest_x;
+
+/** \ingroup msm
+ * Frees the given pointer and sets it to NULL
+ * @param ptr  address of pointer to be freed
+ * @return     
+ */
+void msmFreePointer(void **ptr);
+
+/** \ingroup msm
+ * Process package security manifest.
+ * @param buffer       xml data buffer
+ * @param size         buffer length
+ * @param current      sw source for package
+ * @param packagename  name of the package
+ * @return             pointer to structure on success
+ */
+manifest_x *msmProcessManifestXml(const char *buffer, int size, sw_source_x *current, const char *packagename);
+
+/** \ingroup msm
+ * Process device security policy file.
+ * @param filename     file name
+ * @return             pointer to structure on success
+ */
+manifest_x *msmProcessDevSecPolicyXml(const char *filename);
+
+/** \ingroup msm
+ * Free all structures reserved during manifest processing.
+ * @param mfx          pointer to structure
+ */
+manifest_x* msmFreeManifestXml(manifest_x * mfx);
+
+/** \ingroup msm
+ * Go through all sw sources in manifest, import keys to RPM keyring.
+ * @param smack_accesses       smack_accesses handle for setting smack rules
+ * @param mfx                  package manifest
+ * @param ts                   rpm transaction set
+ * @return                     0 on success, else -1
+ */
+int msmSetupSWSources(struct smack_accesses *smack_accesses, manifest_x *mfx, rpmts ts);
+
+
+/** \ingroup msm
+ * Create package structure for package being installed.
+ * @param name         package name
+ * @param sw_source    package sw source
+ * @param provides     provided ac domains
+ * @param modified     for internal packages
+ * @return             allocated and initialized package struct
+ */
+package_x *msmCreatePackage(const char *name, sw_source_x *sw_source, provide_x *provides, const char *modified);
+
+/** \ingroup msm
+ * Go through all provides in manifest, add provided ac domains to hash.
+ * @param packages     pointer to packages list
+ * @param sw_source    link to sw source in device security policy
+ * @param rule_set     rule set for setting smack rules
+ * @return             0 on success, else -1
+ */
+int msmSetupPackages(struct smack_accesses *smack_accesses, package_x *packages, sw_source_x *sw_source);
+
+/** \ingroup msm
+ * Setup define section of manifest
+ * @param smack_accesses       smack_accesses handle for setting smack rules
+ * @param mfx                  package manifest
+ * @return                     0 on success, else -1
+ */
+int msmSetupDefine(struct smack_accesses *smack_accesses, manifest_x *mfx);
+
+/** \ingroup msm
+ * Setup smack rules according to the manifest
+ * @param smack_accesses       smack_accesses handle for setting smack rules
+ * @param package_name         package name
+ * @param flag                     flag to indicate installation or uninstallation  
+ * @param SmackEnabled      flag to indicate Smack presence in the kernel
+ * @return                             0 on success, else -1
+ */
+int msmSetupSmackRules(struct smack_accesses *smack_accesses, const char* package_name, int flag, int SmackEnabled);
+
+/** \ingroup msm
+ * Check previous installation of package. 
+ * @param name         package name
+ * @return             package or NULL
+ */
+package_x *msmCheckPackage(const char *name);
+
+/** \ingroup msm
+ * Cancel the installation of package (rules and config data). 
+ * @param name         package name
+ */
+void msmCancelPackage(const char *name);
+
+/** \ingroup msm
+ * Free package structure. 
+ * @param package      package
+ * @return             next package in list or NULL
+ */
+package_x *msmFreePackage(package_x *package);
+
+/** \ingroup msm
+ * Set extended attributes of the file based on manifest.
+ * @param mfx          package manifest
+ * @param filepath     path of the file
+ * @param cookie       magic cookie
+ * @return     0 on success, else -1
+ */
+int msmSetFileXAttributes(manifest_x *mfx, const char* filepath, magic_t cookie);
+
+/** \ingroup msm
+ * Set setup the request section of manifest.
+ * @param mfx                  package manifest
+ * @return                     0 on success, else -1
+ */
+int msmSetupRequests(manifest_x *mfx);
+
+/** \ingroup msm
+ * Package is removed, remove all related Smack rules.
+ * @param mfx                  package manifest
+ * @param smack_accesses       smack_accesses handle for setting smack rules
+ * @param SmackEnabled      flag to indicate Smack presence in the kernel
+ */
+void msmRemoveRules(struct smack_accesses *smack_accesses, manifest_x *mfx, int SmackEnabled);
+
+/** \ingroup msm
+ * Setup DBus policies for package
+ * @param package      package 
+ */
+int msmSetupDBusPolicies(package_x *package);
+
+
+/** \ingroup msm
+ * Package is removed, remove related data in device security policy.
+ * @param mfx          package manifest
+ */
+void msmRemoveConfig(manifest_x *mfx);
+
+/** \ingroup msm
+ * String compare which allows wildcards (* and ?) in s2.
+ * @param s1           string to compare
+ * @param s2           string to compare
+ * @return             0 if s1 matches s2
+ */
+int strwcmp(const char *s1, const char *s2);
+
+/** \ingroup msm
+ * Saves configuration into /etc/dev-sec-policy.
+ * @param mfx          data to serialize
+ * @return             RPMRC_OK or RPMRC_FAIL
+ */
+rpmRC msmSaveDeviceSecPolicyXml(manifest_x *root);
+
+/** \ingroup msm
+ * Depth first tree traversal for sw source tree.
+ * @param sw_sources   sw source tree
+ * @param func         function to call for each sw source until 0 is returned
+ * @param param                parameter for the function
+ * @param param2       second parameter for the function
+ * @return             matching sw source or NULL
+ */
+sw_source_x *msmSWSourceTreeTraversal(sw_source_x *sw_sources, int (func)(sw_source_x *, void *, void *), void *param, void* param2);
+
+/** \ingroup msm
+ * Free internal hashes.
+ */
+void msmFreeInternalHashes(void);
+
+/** \ingroup msm
+ * Query that requested package really owns the file.
+ * @param rfor         request for 'package::/file/path'
+ * @param sw_sname     sw source name, caller must free
+ * @param pname                package name, caller must free
+ * @return             pointer to the path part in rfor, or NULL if file
+ *                     is not owned by the specified package
+ */
+const char *msmQueryPackageFile(const char *rfor, 
+                                const char **sw_sname, const char **pname);
+
+
+#endif
diff --git a/plugins/msmconfig.c b/plugins/msmconfig.c
new file mode 100644 (file)
index 0000000..80f8ec4
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * This file is part of MSM security plugin
+ * Greatly based on the code of MSSF security plugin
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Ilhan Gurel <ilhan.gurel@nokia.com>
+ *
+ * Copyright (C) 2011 - 2013 Intel Corporation.
+ *
+ * Contact: Elena Reshetova <elena.reshetova@intel.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; either version 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <libxml/tree.h>
+
+#include "rpmio/rpmbase64.h"
+#include "rpmio/rpmlog.h"
+
+#include "msm.h"
+
+typedef enum credType_e {
+    CRED_ALLOWMATCHES  = 0,
+    CRED_ALLOW         = 1,
+    CRED_DENYMATCHES   = 2,
+    CRED_DENY          = 3,
+    CRED_PROVIDE       = 4
+} credType;
+
+/**
+ * Serializes key data
+ * @todo Problem with getting keydata
+ * @param parent       XML node
+ * @param keyinfo      keyinfo structure
+ * @return             none
+ */
+static void msmHandleKeyinfo(xmlNode *parent, keyinfo_x *keyinfo)
+{    
+    char *enc = NULL;
+
+    if (!parent)
+        return;
+    
+    while (keyinfo) {
+        xmlNode *node = xmlNewNode(NULL, BAD_CAST "keyinfo");
+
+        /* b64 encode keydata first */    
+        if ((enc = rpmBase64Encode(keyinfo->keydata, keyinfo->keylen, -1)) != NULL) {
+            xmlAddChild(node, xmlNewText(BAD_CAST "\n"));        
+            xmlAddChild(node, xmlNewText(BAD_CAST enc));
+            msmFreePointer((void**)&enc);   
+        }
+
+        xmlAddChild(parent, node);
+        keyinfo = keyinfo->prev;
+    }
+}
+
+/**
+ * Serializes ac_domain data
+ * @param parent       XML node
+ * @param type     Type (allow, deny,..)
+ * @param ac_domain    ac_domain structure
+ * @return                 none
+ */
+static void msmHandleACDomains(xmlNode *parent, credType type, 
+                                 ac_domain_x *ac_domain)
+{
+    if (!ac_domain || !parent)
+        return;
+
+    xmlNode *node = NULL;
+
+    if ((type == CRED_ALLOWMATCHES) || (type == CRED_ALLOW)) {
+        node = xmlNewNode(NULL, BAD_CAST "allow");    
+    } else if ((type == CRED_DENYMATCHES) || (type == CRED_DENY)) {
+        node = xmlNewNode(NULL, BAD_CAST "deny"); 
+    } else if (type == CRED_PROVIDE) {
+       node = parent;
+    } else {
+        return;    
+    }
+
+    while (ac_domain) {
+        xmlNode *childnode = xmlNewNode(NULL, BAD_CAST "ac_domain");
+        if ((type == CRED_ALLOWMATCHES) || (type == CRED_DENYMATCHES)) {
+            xmlNewProp(childnode, BAD_CAST "match", BAD_CAST ac_domain->match);
+        } else {
+            xmlNewProp(childnode, BAD_CAST "name", BAD_CAST ac_domain->name);
+           if (ac_domain->type)
+               xmlNewProp(childnode, BAD_CAST "policy", BAD_CAST ac_domain->type);
+           if (ac_domain->plist)
+               xmlNewProp(childnode, BAD_CAST "plist", BAD_CAST ac_domain->plist);
+        }
+        xmlAddChild(node, childnode);
+       if (type == CRED_ALLOW || type == CRED_DENY)
+           ac_domain = ac_domain->hh.next;
+       else
+           ac_domain = ac_domain->prev;
+    }
+
+    if (type != CRED_PROVIDE)
+           xmlAddChild(parent, node);
+}
+
+/**
+ * Serializes origin data
+ * @param parent       XML node
+ * @param origin       origin structure
+ * @return                 none
+ */
+static void msmHandleOrigin(xmlNode *parent, origin_x *origin)
+{    
+    if (!parent)
+        return;
+    
+    while (origin) {
+        xmlNode *node = xmlNewNode(NULL, BAD_CAST "origin");
+        xmlAddChild(parent, node);
+        msmHandleKeyinfo(node, origin->keyinfos);
+        origin = origin->prev;
+    }
+}
+
+/**
+ * Serializes provides data
+ * @param parent       XML node
+ * @param provide      provide structure
+ * @return                 none
+ */
+static void msmHandleProvide(xmlNode *parent, provide_x *provide)
+{    
+    if (!parent)
+        return;     
+
+    while (provide) {
+       if (provide->ac_domains) {
+               xmlNode *node = xmlNewNode(NULL, BAD_CAST "provide");
+               xmlAddChild(parent, node);
+               msmHandleACDomains(node, CRED_PROVIDE, provide->ac_domains);
+               if (provide->origin) {
+                   xmlNode *childnode = xmlNewNode(NULL, BAD_CAST "for");
+                   xmlNewProp(childnode, BAD_CAST "origin", BAD_CAST provide->origin);
+                   xmlAddChild(node, childnode);
+               }
+       }
+        provide = provide->prev;
+    }
+}
+
+/**
+ * Serializes packages data
+ * @param parent       XML node
+ * @param package      package structure
+ * @return             none
+ */
+static void msmHandlePackage(xmlNode *parent, package_x *package)
+{    
+    if (!parent)
+        return; 
+
+    while (package) {
+       if (!package->newer) {
+           xmlNode *node = xmlNewNode(NULL, BAD_CAST "package");
+           xmlNewProp(node, BAD_CAST "name", BAD_CAST package->name);
+           if (package->modified) 
+               xmlNewProp(node, BAD_CAST "modified", BAD_CAST package->modified);
+           xmlAddChild(parent, node);
+           msmHandleProvide(node, package->provides);
+       }
+       package = package->prev;
+    }
+}
+
+/**
+ * Serializes sw source data
+ * @param parent       XML node
+ * @param sw_source    sw_source structure
+ * @return                 none
+ */
+static void msmHandleSWSource(xmlNode *parent, sw_source_x *sw_source)
+{
+    #define MAX_DEPTH 10
+    xmlNode *node[MAX_DEPTH];
+    sw_source_x *temp;
+    int depth = 0;
+
+    if (!sw_source || !parent)
+        return;
+
+    node[0] = parent;
+
+    while (sw_source) {
+       depth = 1; /* recalculate depth */
+       for (temp = sw_source->parent; temp; temp = temp->parent) depth++;
+       if (!sw_source->newer && depth < MAX_DEPTH) {
+           node[depth] = xmlNewNode(NULL, BAD_CAST "sw_source");
+           xmlNewProp(node[depth], BAD_CAST "name", BAD_CAST sw_source->name);
+           xmlNewProp(node[depth], BAD_CAST "rankkey", BAD_CAST sw_source->rankkey);
+           xmlAddChild(node[depth-1], node[depth]);
+           msmHandleOrigin(node[depth], sw_source->origins);
+           msmHandleACDomains(node[depth], CRED_ALLOWMATCHES, sw_source->allowmatches);
+           msmHandleACDomains(node[depth], CRED_ALLOW, sw_source->allows);
+           msmHandleACDomains(node[depth], CRED_DENYMATCHES, sw_source->denymatches);
+           msmHandleACDomains(node[depth], CRED_DENY, sw_source->denys);
+           msmHandlePackage(node[depth], sw_source->packages);
+           if (sw_source->older) {
+               /* packages still belong to this sw_source */
+               msmHandlePackage(node[depth], sw_source->older->packages);
+           }
+       }
+       sw_source = sw_source->next;
+    }
+}
+
+/**
+ * Saves sw_source configuration into /etc/dev-sec-policy.
+ * @param mfx          data to serialize
+ * @return             RPMRC_OK or RPMRC_FAIL
+ */
+rpmRC msmSaveDeviceSecPolicyXml(manifest_x *mfx)
+{    
+    FILE *outFile;
+    rpmRC rc = RPMRC_OK;    
+
+    /* if data doesn't have sw_source information, no need to do anything */    
+    if (mfx && mfx->sw_sources) {    
+       sw_source_x *sw_source;
+       xmlDoc *doc = xmlNewDoc( BAD_CAST "1.0");
+       xmlNode *rootnode = xmlNewNode(NULL, BAD_CAST "config");
+       xmlDocSetRootElement(doc, rootnode);
+
+       LISTHEAD(mfx->sw_sources, sw_source);   
+        msmHandleSWSource(rootnode, sw_source);
+
+        outFile = fopen(DEVICE_SECURITY_POLICY, "w");
+        if (outFile) {
+            xmlElemDump(outFile, doc, rootnode);
+            fclose(outFile);
+        } else {
+            rpmlog(RPMLOG_ERR, "Unable to write device security policy%s\n", 
+                  DEVICE_SECURITY_POLICY);
+            rc = RPMRC_FAIL;
+        }
+        xmlFreeDoc(doc);
+        xmlCleanupParser();
+    }
+
+    return rc;
+}
+
diff --git a/plugins/msmmanifest.c b/plugins/msmmanifest.c
new file mode 100644 (file)
index 0000000..ddba7da
--- /dev/null
@@ -0,0 +1,1501 @@
+/*
+ * This file is part of MSM security plugin
+ * Greatly based on the code of MSSF security plugin
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Tero Aho <ext-tero.aho@nokia.com>
+ *
+ * Copyright (C) 2011 -2013 Intel Corporation.
+ *
+ * Contact: Elena Reshetova <elena.reshetova@intel.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; either version 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <libxml/xmlreader.h>
+#include <sys/capability.h>
+
+#include "msm.h"
+
+#include "rpmio/rpmbase64.h"
+#include "rpmio/rpmlog.h"
+
+/* We'll support only the basic set of characters */
+#define ASCII(s) (const char *)s
+#define XMLCHAR(s) (const xmlChar *)s
+
+
+static int msmVerifyAccessType(const char* type)
+{
+       int res = 0, idx = 0;
+
+       if (type) {
+           if (strlen(type) > SMACK_ACCESS_TYPE_LENGHT) {
+                   rpmlog(RPMLOG_ERR, "Lenght of the access type is bigger than allowed value: %s\n", type);
+                   return -1;
+           }
+           while ( type[idx] != '\0' ){
+               if ((type[idx] !='a') && (type[idx]!='r') && (type[idx]!='w') &&
+                   (type[idx]!='x') && (type[idx]!='t') && (type[idx] !='-')) {
+                   rpmlog(RPMLOG_ERR, "Not allowed character in access type: %s\n", type);
+                   res = -1;
+                   break;
+               }
+               idx++;
+           }
+       } else return -1; 
+       return res;
+}
+
+static int msmVerifySmackLabel(const char* label)
+{
+       int res = 0, idx = 0;
+
+       if (label) {
+           if (strlen(ASCII(label)) > SMACK_LABEL_LENGTH) { //smack limitation on lenght
+               rpmlog(RPMLOG_ERR, "Domain or label name  %s lenght is longer than defined SMACK_LABEL_LENGTH\n", label);
+               return -1; 
+           }
+           if (strlen(ASCII(label)) == 0){
+               rpmlog(RPMLOG_ERR, "An attempt to define an empty domain or label name\n");
+               return -1; 
+           }
+           if (label[0] == '-') {
+               rpmlog(RPMLOG_ERR, "Dash is not allowed as first character in smack label: %s\n", label);
+               return -1;
+           }
+           while ( label[idx] != '\0' ){
+               if ((label[idx] =='\"') || (label[idx] =='\'') || (label[idx] =='/') ||
+                   (label[idx] =='\\') || (label[idx] > '~') || (label[idx] <= ' ')) {
+                   rpmlog(RPMLOG_ERR, "Not allowed character in smack label: %s, position: %d \n", label, idx);
+                   res = -1;
+                   break;
+               }
+               idx++;
+           }
+       } else return -1; 
+
+       return res;
+}
+
+static int msmVerifyLabelPrefix(const char* sub_label, const char* domain_name) 
+{
+    char *tmp = NULL;
+    char sep[]= "::";
+
+    tmp = calloc(strlen(domain_name) + 3, sizeof (const char));
+    if (!tmp) 
+       return -1;
+
+    strncpy(tmp, domain_name, strlen(domain_name));
+    strncpy(tmp + strlen(domain_name), sep, 2);
+
+    if (strstr(ASCII(sub_label), tmp) != ASCII(sub_label)) { //sub label name should be prefixed by domain name and "::"
+       rpmlog(RPMLOG_ERR, "Label name %s isn't prefixed by domain name %s\n", ASCII(sub_label), domain_name);
+       msmFreePointer((void**)&tmp);
+       return -1;
+    } 
+
+    msmFreePointer((void**)&tmp);
+    return 0;
+
+}
+
+static int msmNextChildElement(xmlTextReaderPtr reader, int depth) 
+{
+    int ret = xmlTextReaderRead(reader);
+    int cur = xmlTextReaderDepth(reader);
+    while (ret == 1) {
+       /*
+       rpmlog(RPMLOG_DEBUG, "node %s %d\n", 
+              ASCII(xmlTextReaderConstName(reader)), 
+              xmlTextReaderDepth(reader));
+       */
+       switch (xmlTextReaderNodeType(reader)) {
+       case XML_READER_TYPE_ELEMENT:
+       case XML_READER_TYPE_TEXT:
+           if (cur == depth+1) 
+               return 1;
+           break;
+       case XML_READER_TYPE_END_ELEMENT:
+           if (cur == depth) 
+               return 0;
+           break;
+       default:
+           if (cur <= depth)
+               return 0;
+           break;
+       }
+       ret = xmlTextReaderRead(reader);
+       cur = xmlTextReaderDepth(reader);
+    }
+    return ret;
+}
+
+static ac_domain_x *msmFreeACDomain(ac_domain_x *ac_domain)
+{
+       if (ac_domain) {
+           ac_domain_x *prev = ac_domain->prev;
+           msmFreePointer((void**)&ac_domain->name);
+           msmFreePointer((void**)&ac_domain->type);
+           msmFreePointer((void**)&ac_domain->match);
+           msmFreePointer((void**)&ac_domain->plist);
+           msmFreePointer((void**)&ac_domain);
+           return prev;
+       } else return NULL;
+}
+
+static annotation_x *msmProcessAnnotation(xmlTextReaderPtr reader)
+{
+    const xmlChar *name, *value;
+
+    name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
+    value = xmlTextReaderGetAttribute(reader, XMLCHAR("value"));
+    rpmlog(RPMLOG_DEBUG, "annotation %s %s\n", ASCII(name), ASCII(value));
+
+    if (name && value) {
+           annotation_x *annotation = calloc(1, sizeof(annotation_x));
+           if (annotation) {
+               annotation->name = ASCII(name);
+               annotation->value = ASCII(value);
+               return annotation;
+           }
+    }
+    msmFreePointer((void**)&name);
+    msmFreePointer((void**)&value);
+    return NULL;
+}
+
+static int msmProcessMember(xmlTextReaderPtr reader, member_x *member) 
+{
+    const xmlChar *node, *name;
+    int ret, depth;
+
+    name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
+    rpmlog(RPMLOG_DEBUG, "member %s\n", ASCII(name));
+    member->name = ASCII(name);
+
+    if (!name) return -1;
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+           node = xmlTextReaderConstName(reader);
+           if (!node) return -1;
+
+           if (!strcmp(ASCII(node), "annotation")) {
+               annotation_x *annotation = msmProcessAnnotation(reader);
+               if (annotation) {
+                   member->annotation = annotation;
+               } else return -1;
+           } else return -1;
+
+           if (ret < 0) return -1;
+    }
+    return ret;
+}
+
+static int msmProcessInterface(xmlTextReaderPtr reader, interface_x *interface) 
+{
+    const xmlChar *node, *name;
+    int ret, depth;
+
+    name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
+    rpmlog(RPMLOG_DEBUG, "interface %s\n", ASCII(name));
+    interface->name = ASCII(name);
+
+    if (!name) return -1;
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "method")) {
+           member_x *member = calloc(1, sizeof(member_x));
+           if (member) {
+               member->type = DBUS_METHOD;
+               ret = msmProcessMember(reader, member);
+               LISTADD(interface->members, member);
+           } else return -1;
+       } else if (!strcmp(ASCII(node), "signal")) {
+           member_x *member = calloc(1, sizeof(member_x));
+           if (member) {
+               member->type = DBUS_SIGNAL;
+               ret = msmProcessMember(reader, member);
+               LISTADD(interface->members, member);
+           } else return -1;
+       } else if (!strcmp(ASCII(node), "annotation")) {
+           annotation_x *annotation = msmProcessAnnotation(reader);
+           if (annotation) {
+               interface->annotation = annotation;
+           } else return -1;
+       } else return -1;
+
+       if (ret < 0) return -1;
+    }
+    return ret;
+}
+
+static int msmProcessNode(xmlTextReaderPtr reader, node_x *nodex) 
+{
+    const xmlChar *node, *name;
+    int ret, depth;
+
+    name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
+    rpmlog(RPMLOG_DEBUG, "node %s\n", ASCII(name));
+    nodex->name = ASCII(name);
+
+    if (!name) return -1;
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "interface")) {
+           interface_x *interface = calloc(1, sizeof(interface_x));
+           if (interface) {
+               ret = msmProcessInterface(reader, interface);
+               LISTADD(nodex->interfaces, interface);
+           } else return -1;
+       } else if (!strcmp(ASCII(node), "method")) {
+           member_x *member = calloc(1, sizeof(member_x));
+           if (member) {
+               member->type = DBUS_METHOD;
+               ret = msmProcessMember(reader, member);
+               LISTADD(nodex->members, member);
+           } else return -1;
+       } else if (!strcmp(ASCII(node), "signal")) {
+           member_x *member = calloc(1, sizeof(member_x));
+           if (member) {
+               member->type = DBUS_SIGNAL;
+               ret = msmProcessMember(reader, member);
+               LISTADD(nodex->members, member);
+           } else return -1;
+       } else if (!strcmp(ASCII(node), "annotation")) {
+           annotation_x *annotation = msmProcessAnnotation(reader);
+           if (annotation) {
+               nodex->annotation = annotation;
+           } else return -1;
+       } else return -1;
+
+       if (ret < 0) return -1;
+    }
+    return ret;
+}
+
+static int msmProcessDBus(xmlTextReaderPtr reader, dbus_x *dbus) 
+{
+    const xmlChar *node, *name, *own, *bus;
+    int ret, depth;
+
+    name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
+    own = xmlTextReaderGetAttribute(reader, XMLCHAR("own"));
+    bus = xmlTextReaderGetAttribute(reader, XMLCHAR("bus"));
+    rpmlog(RPMLOG_DEBUG, "dbus %s %s %s\n", ASCII(name), ASCII(own), ASCII(bus));
+    dbus->name = ASCII(name);
+    dbus->own = ASCII(own);
+    dbus->bus = ASCII(bus);    
+
+    if (!name || !bus) return -1;
+    if (strcmp(dbus->bus, "session") && strcmp(dbus->bus, "system"))
+       return -1;
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "node")) {
+           node_x *nodex = calloc(1, sizeof(node_x));
+           if (nodex) {
+               ret = msmProcessNode(reader, nodex);
+               LISTADD(dbus->nodes, nodex);
+           } else return -1;
+       } else if (!strcmp(ASCII(node), "annotation")) {
+           annotation_x *annotation = msmProcessAnnotation(reader);
+           if (annotation) {
+               dbus->annotation = annotation;
+           } else return -1;
+       } else return -1;
+
+       if (ret < 0) return -1;
+    }
+    return ret;
+}
+
+static ac_domain_x *msmProcessACDomain(xmlTextReaderPtr reader, sw_source_x *sw_source, const char* pkg_name)
+{
+    const xmlChar *name, *match, *policy, *plist;
+
+    name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
+    match = xmlTextReaderGetAttribute(reader, XMLCHAR("match"));
+    policy = xmlTextReaderGetAttribute(reader, XMLCHAR("policy"));
+    plist = xmlTextReaderGetAttribute(reader, XMLCHAR("plist"));
+    rpmlog(RPMLOG_DEBUG, "ac_domain %s match %s policy %s plist %s\n", ASCII(name), ASCII(match), ASCII(policy), ASCII(plist));
+
+    if (!((!name && !match) || (name && match))) {
+       ac_domain_x *ac_domain = calloc(1, sizeof(ac_domain_x));
+       if (ac_domain) {
+           ac_domain->name = ASCII(name);
+           ac_domain->match = ASCII(match);
+           ac_domain->type = ASCII(policy);
+           ac_domain->plist = ASCII(plist);
+           ac_domain->sw_source = sw_source;
+           ac_domain->pkg_name = pkg_name;     
+           return ac_domain;
+       }
+    }
+    rpmlog(RPMLOG_ERR, "Mandatory argument is missing for ac domain definition\n");
+    rpmlog(RPMLOG_ERR, "ac_domain %s match %s policy %s plist %s\n", ASCII(name), ASCII(match), ASCII(policy), ASCII(plist));
+    msmFreePointer((void**)&name);
+    msmFreePointer((void**)&match);
+    msmFreePointer((void**)&policy);
+    msmFreePointer((void**)&plist);
+    return NULL;
+}
+
+static filesystem_x *msmProcessFilesystem(xmlTextReaderPtr reader)
+{
+    const xmlChar *path, *label, *type, *exec_label;
+
+    path = xmlTextReaderGetAttribute(reader, XMLCHAR("path"));
+    label = xmlTextReaderGetAttribute(reader, XMLCHAR("label"));
+    exec_label = xmlTextReaderGetAttribute(reader, XMLCHAR("exec_label"));
+    type = xmlTextReaderGetAttribute(reader, XMLCHAR("type"));
+
+    rpmlog(RPMLOG_DEBUG, "filesystem path %s label %s exec label %s type %s\n", 
+          ASCII(path), ASCII(label), ASCII(exec_label), ASCII(type));
+
+   if (path && (label || exec_label)) {
+       if ((label) && (msmVerifySmackLabel(ASCII(label)) < 0)) {
+               goto fail;
+       }
+       if ((exec_label) && (msmVerifySmackLabel(ASCII(exec_label)) < 0)) {
+               goto fail;
+       }
+
+       filesystem_x *filesystem = calloc(1, sizeof(filesystem_x));
+       if (filesystem) {
+           filesystem->path = ASCII(path);
+           filesystem->label = ASCII(label);
+           filesystem->exec_label = ASCII(exec_label);
+           filesystem->type = ASCII(type);
+           return filesystem;
+       }
+
+    } else {
+       rpmlog(RPMLOG_ERR, "Mandatory argument is missing for filesystem assign request\n");
+       rpmlog(RPMLOG_ERR, "filesystem path %s label %s exec label %s\n", 
+          ASCII(path), ASCII(label), ASCII(exec_label));
+    }
+
+fail:
+    msmFreePointer((void**)&path);
+    msmFreePointer((void**)&label);
+    msmFreePointer((void**)&exec_label);
+    msmFreePointer((void**)&type);
+    return NULL;
+}
+
+static int msmProcessProvide(xmlTextReaderPtr reader, provide_x *provide, sw_source_x *current, manifest_x *mfx, const char* pkg_name)
+{
+    const xmlChar *node, *name, *origin;
+    int ret, depth;
+
+    name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
+    rpmlog(RPMLOG_DEBUG, "assign %s\n", ASCII(name));
+    provide->name = ASCII(name);
+
+    if (provide->name && 
+       (strcmp(provide->name, "_system_") || mfx->sw_source->parent))
+       return -1; /* only _system_ is accepted from root sw source */
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "dbus")) {
+           dbus_x *dbus = calloc(1, sizeof(dbus_x));
+           if (dbus) {
+               ret = msmProcessDBus(reader, dbus);
+               LISTADD(provide->dbuss, dbus);
+           } else return -1;
+       } else if (!strcmp(ASCII(node), "ac_domain")) {
+           ac_domain_x *ac_domain = msmProcessACDomain(reader, current, pkg_name);
+           if (ac_domain) {
+               const char *name = ac_domain->name;
+               LISTADD(provide->ac_domains, ac_domain);
+               if (!name) return -1;
+               if (mfx && !provide->name) {
+                   ac_domain->name = malloc(strlen(mfx->name) + 2 +
+                                             strlen(name) + 1);
+                   sprintf((char *)ac_domain->name, "%s::%s", mfx->name, name);
+                   msmFreePointer((void**)&name);
+               }
+           } else return -1;
+
+       } else if (!strcmp(ASCII(node), "for")) {
+           origin = xmlTextReaderGetAttribute(reader, XMLCHAR("origin"));
+           rpmlog(RPMLOG_DEBUG, "for %s\n", ASCII(origin));
+           if (!origin) return -1;
+           if (provide->origin) { 
+               msmFreePointer((void**)&origin);
+               return -1;
+           }
+           provide->origin = ASCII(origin);
+           if (strcmp(ASCII(origin), "trusted") && 
+               strcmp(ASCII(origin), "current") &&
+               strcmp(ASCII(origin), "all"))
+               return -1;
+
+       } else if (!strcmp(ASCII(node), "filesystem")) {
+           filesystem_x *filesystem = msmProcessFilesystem(reader);
+           if (filesystem) {
+               LISTADD(provide->filesystems, filesystem);
+           } else return -1;
+
+       } else {
+               rpmlog(RPMLOG_ERR, "No allowed element in assign section: %s\n", ASCII(node));
+               return -1;
+       }
+
+       if (ret < 0) return ret;
+    }
+
+    return ret;
+}
+
+static int msmProcessPackage(xmlTextReaderPtr reader, package_x *package, sw_source_x *current)
+{
+    const xmlChar *node, *name, *modified;
+    int ret, depth;
+
+    /* config processing */
+    name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
+    modified = xmlTextReaderGetAttribute(reader, XMLCHAR("modified"));
+    rpmlog(RPMLOG_DEBUG, "package %s %s\n", name, modified);
+
+    package->name = ASCII(name);
+    package->modified = ASCII(modified);
+    package->sw_source = current;
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "provide")) {
+           provide_x *provide = calloc(1, sizeof(provide_x));
+           if (provide) {
+               LISTADD(package->provides, provide);
+               ret = msmProcessProvide(reader, provide, current, NULL, package->name);
+           } else return -1;
+       } else return -1;
+
+       if (ret < 0) return ret;
+    }
+    return ret;
+}
+
+static int msmProcessRequest(xmlTextReaderPtr reader, request_x *request) 
+{
+    const xmlChar *node, *name;
+    int ret, depth, requestPresent = 0;
+
+    rpmlog(RPMLOG_DEBUG, "request \n");
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+           if (!strcmp(ASCII(node), "domain")) {
+               if (requestPresent) {
+                       rpmlog(RPMLOG_ERR, "A second domain defined inside a request section. Abort package installation\n");
+                       return -1;
+               }
+               name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));   
+               rpmlog(RPMLOG_DEBUG, "ac domain name %s\n", ASCII(name));
+               if (name) {
+                       request->ac_domain = ASCII(name);
+                       requestPresent = 1;
+               } else {
+                       rpmlog(RPMLOG_ERR, "No ac domain name defined in request.\n");
+                       return -1;
+               }
+           } else {
+               rpmlog(RPMLOG_ERR, "Not allowed element in request section: %s\n", ASCII(node));
+               return -1;
+           }
+    }
+    
+    return ret;
+}
+
+static int msmProcessDRequest(xmlTextReaderPtr reader, define_x *define) 
+{
+    const xmlChar *node = NULL, *label = NULL, *type = NULL;
+    int ret, depth;
+
+    rpmlog(RPMLOG_DEBUG, "request\n");
+
+    if (!define->name) {
+        rpmlog(RPMLOG_ERR, "An attempt to define a domain without a name. Abort.\n");
+        return -1;
+    }
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "smack")) {
+           label = xmlTextReaderGetAttribute(reader, XMLCHAR("request"));
+           type = xmlTextReaderGetAttribute(reader, XMLCHAR("type"));
+           rpmlog(RPMLOG_DEBUG, "request label %s type %s\n", ASCII(label), ASCII(type));
+           if (label && type) {
+                   if (msmVerifyAccessType(ASCII(type)) < 0) {
+                       msmFreePointer((void**)&label);
+                       msmFreePointer((void**)&type);  
+                       return -1; 
+                   }
+                   if (msmVerifySmackLabel(ASCII(label)) < 0) {
+                       msmFreePointer((void**)&label);
+                       msmFreePointer((void**)&type);
+                       return -1;
+                   }
+                   d_request_x *request = calloc(1, sizeof(d_request_x));
+                   if (request) {
+                       request->label_name = ASCII(label);
+                       request->ac_type = ASCII(type);
+                       LISTADD(define->d_requests, request);
+                   } else {
+                       msmFreePointer((void**)&label);
+                       msmFreePointer((void**)&type);
+                       return -1;
+                   }
+
+           } else  {
+                   rpmlog(RPMLOG_ERR, "One of the mandatory arguments for domain request is missing. Abort installation\n");
+                   rpmlog(RPMLOG_ERR, "smack request label %s type %s\n", ASCII(label), ASCII(type));
+                   msmFreePointer((void**)&label);
+                   msmFreePointer((void**)&type);      
+                   return -1;
+           }
+       } else {
+               rpmlog(RPMLOG_ERR, "Not allowed element in domain request section: %s\n", ASCII(node));
+               return -1;
+       }
+       if (ret < 0) return ret;
+    }
+
+    return ret;
+}
+
+static int msmProcessDPermit(xmlTextReaderPtr reader, define_x *define) 
+{
+    const xmlChar *node, *label, *type, *to_label;
+    int ret, depth;
+
+    rpmlog(RPMLOG_DEBUG, "permit\n");
+
+    if (!define->name) {
+        rpmlog(RPMLOG_ERR, "An attempt to define a domain without a name. Abort.\n");
+        return -1;
+    }
+
+    depth = xmlTextReaderDepth(reader);
+
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "smack")) {
+           label = xmlTextReaderGetAttribute(reader, XMLCHAR("permit"));
+           to_label = xmlTextReaderGetAttribute(reader, XMLCHAR("to"));
+           type = xmlTextReaderGetAttribute(reader, XMLCHAR("type"));
+           rpmlog(RPMLOG_DEBUG, "permit %s to %s type %s\n", ASCII(label), ASCII(to_label), ASCII(type));
+
+           if (label && type) {
+                   if (msmVerifyAccessType(ASCII(type)) < 0) {
+                       msmFreePointer((void**)&label);
+                       msmFreePointer((void**)&to_label);
+                       msmFreePointer((void**)&type);  
+                       return -1; 
+                   }
+                   if (msmVerifySmackLabel(ASCII(label)) < 0) {
+                       msmFreePointer((void**)&label);
+                       msmFreePointer((void**)&to_label);
+                       msmFreePointer((void**)&type);
+                       return -1;
+                   }
+                   if ((to_label) && (msmVerifyLabelPrefix(ASCII(to_label), define->name) < 0)) {
+                       msmFreePointer((void**)&label);
+                       msmFreePointer((void**)&to_label);
+                       msmFreePointer((void**)&type);
+                       return -1;
+                   }
+                   d_permit_x *permit = calloc(1, sizeof(d_permit_x));
+                   if (permit) {
+                       permit->label_name = ASCII(label);
+                       permit->to_label_name = ASCII(to_label);
+                       permit->ac_type = ASCII(type);
+                       LISTADD(define->d_permits, permit);
+                   } else {
+                       msmFreePointer((void**)&label);
+                       msmFreePointer((void**)&to_label);
+                       msmFreePointer((void**)&type);
+                       return -1;
+                   }
+
+           } else  {
+                   rpmlog(RPMLOG_ERR, "One of the mandatory arguments for domain permit is missing. Abort installation\n");
+                   rpmlog(RPMLOG_ERR, "smack permit label %s type %s\n", ASCII(label), ASCII(type));
+                   msmFreePointer((void**)&label);
+                   msmFreePointer((void**)&to_label);
+                   msmFreePointer((void**)&type);      
+                   return -1;
+           }
+       } else {
+               rpmlog(RPMLOG_ERR, "Not allowed element in domain permit section: %s\n", ASCII(node));
+               return -1;
+       }
+       if (ret < 0) return ret;
+    }
+
+    return ret;
+}
+
+static int msmProcessDProvide(xmlTextReaderPtr reader, define_x *define) 
+{
+    const xmlChar *node, *label;
+    int ret = 0, depth;
+
+    rpmlog(RPMLOG_DEBUG, "provide\n");
+
+    if (!define->name) {
+        rpmlog(RPMLOG_ERR, "An attempt to define a domain without a name. Abort.\n");
+        return -1;
+    }
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "label")) {
+           label = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
+           rpmlog(RPMLOG_DEBUG, "label %s \n", ASCII(label));
+
+           if (label) {
+                   if (msmVerifySmackLabel(ASCII(label)) < 0) {
+                       msmFreePointer((void**)&label);
+                       return -1;
+                   }
+
+                   if (msmVerifyLabelPrefix(ASCII(label), define->name) < 0) {
+                       msmFreePointer((void**)&label);
+                       return -1;
+                   }
+
+                   d_provide_x *provide = calloc(1, sizeof(d_provide_x));
+                   if (provide) {
+                       provide->label_name = ASCII(label);
+                       LISTADD(define->d_provides, provide);
+                   } else {
+                       msmFreePointer((void**)&label);
+                       return -1;
+                   }
+
+           } else  {
+                   rpmlog(RPMLOG_INFO, "Label name is empty. Label provide is ignored\n");
+                   continue;
+           }
+       } else {
+               rpmlog(RPMLOG_ERR, "Not allowed element in domain provide section: %s\n", ASCII(node));
+               return -1;
+       }
+       if (ret < 0) return ret;
+    }
+
+    return ret;
+}
+
+static int msmProcessDefine(xmlTextReaderPtr reader, define_x *define, manifest_x *mfx, sw_source_x *current) 
+{
+    const xmlChar *node, *name, *policy, *plist;
+    int ret, depth, domainPresent = 0;
+
+    rpmlog(RPMLOG_DEBUG, "define\n");
+
+    depth = xmlTextReaderDepth(reader);
+
+    while ((ret = msmNextChildElement(reader, depth))) {
+           node = xmlTextReaderConstName(reader);
+           if (!node) return -1;
+
+           if (!strcmp(ASCII(node), "domain")) {
+                   if (domainPresent) {
+                       rpmlog(RPMLOG_ERR, "Only one domain is allowed per define section. Abort installation\n");
+                       return -1;
+                   }
+                   domainPresent = 1;
+                   name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
+                   policy = xmlTextReaderGetAttribute(reader, XMLCHAR("policy"));
+                   plist = xmlTextReaderGetAttribute(reader, XMLCHAR("plist"));
+                   rpmlog(RPMLOG_DEBUG, "domain %s policy %s plist %s\n", 
+                          ASCII(name), ASCII(policy), ASCII(plist));
+
+                   if (name) { 
+                   
+                           if (msmVerifySmackLabel(ASCII(name)) < 0){
+                               msmFreePointer((void**)&name);
+                               msmFreePointer((void**)&policy);                
+                               msmFreePointer((void**)&plist);
+                               return -1; 
+                           }
+
+                           define->name = ASCII(name);
+                           define->policy = ASCII(policy);
+                           define->plist = ASCII(plist);
+
+                           // store defined ac domain name 
+                           ac_domain_x *ac_domain = calloc(1, sizeof(ac_domain_x));
+                           if (ac_domain) {
+                                   if (define->name) {
+                                       ac_domain->name = strdup(define->name);
+                                   }
+                                   ac_domain->match = strdup("trusted"); // hardcode trusted policy for ac domain definition
+                                   if (define->policy) {
+                                       ac_domain->type = strdup(define->policy);
+                                   }   
+                                   if (define->plist) {
+                                       ac_domain->plist = strdup(define->plist);
+                                   }                             
+                                   ac_domain->sw_source = current;
+                                   ac_domain->pkg_name = mfx->name;
+                                   if (!mfx->provides){
+                                       provide_x *provide = calloc(1, sizeof(provide_x));
+                                       if (provide) {
+                                               LISTADD(mfx->provides, provide);
+                                       } else { 
+                                               if (ac_domain) {
+                                                       msmFreeACDomain(ac_domain);
+                                                       return -1;
+                                               }
+                                       }
+                                   }
+                                   LISTADD(mfx->provides->ac_domains, ac_domain);
+                           } else return -1;
+
+                   } else  {
+                           rpmlog(RPMLOG_ERR, "Domain name must be defined. Abort installation\n");
+                           msmFreePointer((void**)&policy);    
+                           msmFreePointer((void**)&plist);
+                           return -1; 
+                   }
+           } else if (!strcmp(ASCII(node), "request")) {
+                   int res = msmProcessDRequest(reader, define);
+                   if (res < 0) return res;
+           
+           } else if (!strcmp(ASCII(node), "permit")) {
+                   int res = msmProcessDPermit(reader, define);
+                   if (res < 0) return res;
+
+           } else if (!strcmp(ASCII(node), "provide")) {
+                   int res = msmProcessDProvide(reader, define);
+                   if (res < 0) return res;
+           } else {
+               rpmlog(RPMLOG_ERR, "Not allowed element in domain define section: %s\n", ASCII(node));
+               return -1;
+       }
+
+       if (ret < 0) return ret;
+    }
+    return ret;
+}
+
+static int msmProcessKeyinfo(xmlTextReaderPtr reader, origin_x *origin) 
+{
+    const xmlChar *keydata;
+    keyinfo_x *keyinfo;
+    int ret, depth;
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       keydata = xmlTextReaderConstValue(reader);
+       rpmlog(RPMLOG_DEBUG, "keyinfo %.40s...\n", ASCII(keydata));
+       if (!keydata) return -1;
+       keyinfo = calloc(1, sizeof(keyinfo_x));
+       if (keyinfo) {
+           if ((ret = rpmBase64Decode(ASCII(keydata), (void **)&keyinfo->keydata, &keyinfo->keylen))) {
+               rpmlog(RPMLOG_ERR, "Failed to decode keyinfo %s, %d\n", keydata, ret);
+               ret = -1;
+           }
+           LISTADD(origin->keyinfos, keyinfo);
+       } else return -1;
+
+       if (ret < 0) return ret;
+    }
+    return ret;
+}
+
+static access_x *msmProcessAccess(xmlTextReaderPtr reader, origin_x *origin) 
+{
+    const xmlChar *data, *type;
+
+    data = xmlTextReaderGetAttribute(reader, XMLCHAR("data"));
+    type = xmlTextReaderGetAttribute(reader, XMLCHAR("type"));
+    rpmlog(RPMLOG_DEBUG, "access %s %s\n", ASCII(data), ASCII(type));
+
+    if (data) {
+       access_x *access = calloc(1, sizeof(access_x));
+       if (access) {
+           access->data = ASCII(data);
+           access->type = ASCII(type);
+           return access;
+       }
+    }
+    msmFreePointer((void**)&data);
+    msmFreePointer((void**)&type);
+    return NULL;
+}
+
+static int msmProcessOrigin(xmlTextReaderPtr reader, origin_x *origin) 
+{
+    const xmlChar *node, *type;
+    int ret, depth;
+
+    type = xmlTextReaderGetAttribute(reader, XMLCHAR("type"));
+    rpmlog(RPMLOG_DEBUG, "origin %s\n", ASCII(type));
+    origin->type = ASCII(type);
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "keyinfo")) {
+           ret = msmProcessKeyinfo(reader, origin);
+       } else if (!strcmp(ASCII(node), "access")) {
+           access_x *access = msmProcessAccess(reader, origin);
+           if (access) {
+               LISTADD(origin->accesses, access);
+           } else return -1;
+       } else return -1;
+
+       if (ret < 0) return ret;
+    }
+    return ret;
+}
+
+static int msmProcessDeny(xmlTextReaderPtr reader, sw_source_x *sw_source) 
+{
+    const xmlChar *node;
+    int ret, depth;
+
+    rpmlog(RPMLOG_DEBUG, "deny\n");
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "ac_domain")) {
+           ac_domain_x *ac_domain = msmProcessACDomain(reader, sw_source, NULL);
+           if (ac_domain) {
+               if (ac_domain->name) {
+                   HASH_ADD_KEYPTR(hh, sw_source->denys, ac_domain->name, 
+                                   strlen(ac_domain->name), ac_domain);
+               } else {
+                   LISTADD(sw_source->denymatches, ac_domain);
+               }
+           } else return -1;
+       } else return -1;
+       if (ret < 0) return ret;
+    }
+    return ret;
+}
+
+static int msmProcessAllow(xmlTextReaderPtr reader, sw_source_x *sw_source) 
+{
+    const xmlChar *node;    
+    int ret, depth;
+
+    rpmlog(RPMLOG_DEBUG, "allow\n");
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "deny")) {
+           ret = msmProcessDeny(reader, sw_source);
+       } else if (!strcmp(ASCII(node), "ac_domain")) {
+           ac_domain_x *ac_domain = msmProcessACDomain(reader, sw_source, NULL);
+           if (ac_domain) {
+               if (ac_domain->name) {
+                   HASH_ADD_KEYPTR(hh, sw_source->allows, ac_domain->name, 
+                                   strlen(ac_domain->name), ac_domain);
+               } else {
+                   LISTADD(sw_source->allowmatches, ac_domain);
+               }
+           } else return -1;
+       } else return -1;
+       if (ret < 0) return ret;
+    }
+    return ret;
+}
+
+static int msmFindSWSourceByName(sw_source_x *sw_source, void *param)
+{
+    const char *name = (const char *)param;
+    return strcmp(sw_source->name, name); 
+}
+
+static int msmProcessSWSource(xmlTextReaderPtr reader, sw_source_x *sw_source, const char *parentkey, manifest_x *mfx) 
+{
+    const xmlChar *name, *node, *rank, *rankkey;
+    sw_source_x *current;
+    int ret, depth, len;
+    int rankval = 0;
+
+    /* config processing */
+    current = sw_source;
+
+    name = xmlTextReaderGetAttribute(reader, XMLCHAR("name"));
+    rank = xmlTextReaderGetAttribute(reader, XMLCHAR("rank"));
+    rankkey = xmlTextReaderGetAttribute(reader, XMLCHAR("rankkey"));
+    rpmlog(RPMLOG_DEBUG, "sw source %s rank %s key %s\n", 
+          ASCII(name), ASCII(rank), ASCII(rankkey));
+
+    sw_source->name = ASCII(name);
+
+    if (rankkey) {
+       /* config processing */
+       sw_source->rankkey = ASCII(rankkey);
+    } else {
+       if (rank) {
+           rankval = atoi(ASCII(rank));
+           msmFreePointer((void**)&rank); /* rankkey is used from now on */
+       }
+    }
+    if (!sw_source->name) return -1; /* sw source must have name */
+    if (!mfx && rankkey) return -1; /* manifest cannot set rankkey itself */
+
+    if (!mfx) {
+       sw_source_x *old = msmSWSourceTreeTraversal(sw_source->parent, msmFindSWSourceByName, (void *)sw_source->name, NULL);
+       if (old && old->parent != sw_source->parent) {
+           if (!old->parent && old == sw_source->parent) {
+               /* root sw source upgrade (it's signed by root) */
+               parentkey = "";
+           } else {
+               rpmlog(RPMLOG_ERR, "SW source called %s has already been installed\n", 
+                      sw_source->name);
+               return -1; /* sw_source names are unique (allow upgrade though) */
+           }
+       }
+       /* rank algorithm is copied from harmattan dpkg wrapper */
+       if (rankval > RANK_LIMIT) rankval = RANK_LIMIT;
+       if (rankval < -RANK_LIMIT) rankval = -RANK_LIMIT;
+       rankval += RANK_LIMIT;
+
+       len = strlen(parentkey) + 1 + 5 + 1 + 5 + 1 + strlen(sw_source->name) + 1;
+       if (!(sw_source->rankkey = malloc(len))) return -1;
+       sprintf((char *)sw_source->rankkey, "%s/%05d/%05d.%s", 
+               parentkey, rankval, RANK_LIMIT, sw_source->name);
+    }
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "allow")) {
+           ret = msmProcessAllow(reader, sw_source);
+       } else if (!strcmp(ASCII(node), "deny")) {
+           ret = msmProcessDeny(reader, sw_source);
+       } else if (!strcmp(ASCII(node), "origin")) {
+           origin_x *origin = calloc(1, sizeof(origin_x));
+           if (origin) {
+               LISTADD(sw_source->origins, origin);
+               ret = msmProcessOrigin(reader, origin);
+           } else return -1;
+       } else if (!strcmp(ASCII(node), "package")) {
+           /* config processing */
+           if (!mfx) return -1;
+           package_x *package = calloc(1, sizeof(package_x));
+           if (package) {
+               LISTADD(sw_source->packages, package);
+               ret = msmProcessPackage(reader, package, current);
+           } else return -1;
+       } else if (!strcmp(ASCII(node), "sw_source")) {
+           /* config processing */
+           if (!mfx) return -1;
+           sw_source_x *sw_source = calloc(1, sizeof(sw_source_x));
+           if (sw_source) {
+               sw_source->parent = current;
+               LISTADD(mfx->sw_sources, sw_source);
+           } else return -1;
+           ret = msmProcessSWSource(reader, sw_source, "", mfx);
+       } else return -1;
+
+       if (ret < 0) return ret;
+    }
+    return ret;
+}
+
+static int msmProcessMsm(xmlTextReaderPtr reader, manifest_x *mfx, sw_source_x *current)
+{
+    const xmlChar *node;
+    int ret, depth;
+    int assignPresent = 0, requestPresent = 0, definePresent = 0; /* there must be only one section per manifest */
+    mfx->sw_source = current;
+
+    rpmlog(RPMLOG_DEBUG, "manifest\n");
+
+    depth = xmlTextReaderDepth(reader);
+    while ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "assign")) {
+               if (assignPresent) {
+                       rpmlog(RPMLOG_ERR, "A second assign section in manifest isn't allowed. Abort installation.\n");
+                       return -1; 
+               }
+               assignPresent = 1;
+               provide_x *provide = calloc(1, sizeof(provide_x));
+               if (provide) {
+                       LISTADD(mfx->provides, provide);
+                       ret = msmProcessProvide(reader, provide, current, mfx, NULL);
+               } else return -1;
+       } else if (!strcmp(ASCII(node), "define")) {
+               if (definePresent) {
+                       rpmlog(RPMLOG_ERR, "A second request section in manifest isn't allowed. Abort installation.\n");
+                       return -1; 
+               }
+               definePresent = 1;
+               mfx->define = calloc(1, sizeof(define_x));
+               if (mfx->define) {
+                       ret = msmProcessDefine(reader, mfx->define, mfx, current);
+               } else return -1;
+       } else if (!strcmp(ASCII(node), "request")) {
+               if (requestPresent) {
+                       rpmlog(RPMLOG_ERR, "A second request section in manifest isn't allowed. Abort installation.\n");
+                       return -1; 
+               }
+               requestPresent = 1;
+               mfx->request = calloc(1, sizeof(request_x));
+               if (mfx->request) {
+                       ret = msmProcessRequest(reader, mfx->request);
+               } else return -1;
+       } else if (!strcmp(ASCII(node), "sw_source")) {
+           sw_source_x *sw_source = calloc(1, sizeof(sw_source_x));
+           if (sw_source) {
+               char parentkey[256] = { 0 };
+               sw_source->parent = current;
+               if (sw_source->parent) {
+                   snprintf(parentkey, sizeof(parentkey), 
+                            "%s", sw_source->parent->rankkey);
+                   char *sep = strrchr(parentkey, '/');
+                   if (sep) *sep = '\0';
+               }
+               LISTADD(mfx->sw_sources, sw_source);
+               ret = msmProcessSWSource(reader, sw_source, parentkey, NULL);
+           } else return -1;
+       } else return -1;
+
+       if (ret < 0) return ret;
+    }
+
+    return ret;
+}
+
+static int msmProcessConfig(xmlTextReaderPtr reader, manifest_x *mfx)
+{
+    const xmlChar *node;
+    int ret, depth;
+
+    rpmlog(RPMLOG_DEBUG, "config\n");
+
+    depth = xmlTextReaderDepth(reader);
+    if ((ret = msmNextChildElement(reader, depth))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "sw_source")) {
+           mfx->sw_sources = calloc(1, sizeof(sw_source_x));
+           if (!mfx->sw_sources) return -1;
+           ret = msmProcessSWSource(reader, mfx->sw_sources, "", mfx);
+       } else return -1;
+    }
+    return ret;
+}
+
+static int msmProcessManifest(xmlTextReaderPtr reader, manifest_x *mfx, sw_source_x *current) 
+{
+    const xmlChar *node;
+    int ret;
+
+    if ((ret = msmNextChildElement(reader, -1))) {
+       node = xmlTextReaderConstName(reader);
+       if (!node) return -1;
+
+       if (!strcmp(ASCII(node), "manifest")) {
+           ret = msmProcessMsm(reader, mfx, current);
+       } else if (!strcmp(ASCII(node), "config")) {
+           ret = msmProcessConfig(reader, mfx);
+       } else return -1;
+    }
+    return ret;
+}
+
+static filesystem_x *msmFreeFilesystem(filesystem_x *filesystem)
+{    
+       if (filesystem) {
+           filesystem_x *prev = filesystem->prev;
+           msmFreePointer((void**)&filesystem->path);
+           msmFreePointer((void**)&filesystem->label);
+           msmFreePointer((void**)&filesystem->exec_label);
+           msmFreePointer((void**)&filesystem->type);
+           msmFreePointer((void**)&filesystem);
+           return prev;
+       } else
+               return NULL;
+
+}
+
+static member_x *msmFreeMember(member_x *member)
+{    
+
+       if (member) {
+           member_x *prev = member->prev;
+           msmFreePointer((void**)&member->name);
+           if (member->annotation) {
+               msmFreePointer((void**)&member->annotation->name);
+               msmFreePointer((void**)&member->annotation->value);
+               msmFreePointer((void**)&member->annotation);
+           }
+           msmFreePointer((void**)&member);
+           return prev;
+       } else
+               return NULL;
+
+}
+
+static interface_x *msmFreeInterface(interface_x *interface)
+{    
+
+       member_x *member;
+
+       if (interface) {
+           interface_x *prev = interface->prev;
+           msmFreePointer((void**)&interface->name);
+           if (interface->annotation) {
+               msmFreePointer((void**)&interface->annotation->name);
+               msmFreePointer((void**)&interface->annotation->value);
+               msmFreePointer((void**)&interface->annotation);
+           }
+           for (member = interface->members; member; member = msmFreeMember(member));
+           msmFreePointer((void**)&interface);
+           return prev;
+       } else
+               return NULL;
+
+}
+
+static node_x *msmFreeNode(node_x *node)
+{    
+       member_x *member;
+       interface_x *interface;
+
+       if (node) {
+           node_x *prev = node->prev;
+           msmFreePointer((void**)&node->name);
+           if (node->annotation) {
+               msmFreePointer((void**)&node->annotation->name);
+               msmFreePointer((void**)&node->annotation->value);
+               msmFreePointer((void**)&node->annotation);
+           }
+           for (member = node->members; member; member = msmFreeMember(member));
+           for (interface = node->interfaces; interface; interface = msmFreeInterface(interface));
+           msmFreePointer((void**)&node);
+           return prev;
+       } else
+               return NULL;
+
+}
+
+static dbus_x *msmFreeDBus(dbus_x *dbus)
+{
+       node_x *node;
+
+       if (dbus) {
+           dbus_x *prev = dbus->prev;
+           msmFreePointer((void**)&dbus->name);
+           msmFreePointer((void**)&dbus->own);
+           msmFreePointer((void**)&dbus->bus);
+            if (dbus->annotation) {
+               msmFreePointer((void**)&dbus->annotation->name);
+               msmFreePointer((void**)&dbus->annotation->value);
+               msmFreePointer((void**)&dbus->annotation);
+           }
+           for (node = dbus->nodes; node; node = msmFreeNode(node));
+           msmFreePointer((void**)&dbus);
+           return prev;
+       } else return NULL;
+}
+
+static provide_x *msmFreeProvide(provide_x *provide) 
+{
+    ac_domain_x *ac_domain;
+    filesystem_x *filesystem;
+    provide_x *prev = provide->prev;
+    dbus_x *dbus;
+
+    if (provide) {
+           for (ac_domain = provide->ac_domains; ac_domain; ac_domain = msmFreeACDomain(ac_domain));
+           if (provide->filesystems)
+               for (filesystem = provide->filesystems; filesystem; filesystem = msmFreeFilesystem(filesystem));
+           msmFreePointer((void**)&provide->name);
+           msmFreePointer((void**)&provide->origin);
+           for (dbus = provide->dbuss; dbus; dbus = msmFreeDBus(dbus));
+           msmFreePointer((void**)&provide);
+    }
+    return prev;
+}
+
+static file_x *msmFreeFile(file_x *file)
+{
+    file_x *prev = file->prev;
+    msmFreePointer((void**)&file->path);
+    msmFreePointer((void**)&file);
+    return prev;
+}
+
+package_x *msmFreePackage(package_x *package)
+{
+    provide_x *provide;
+    package_x *prev = package->prev;
+    for (provide = package->provides; provide; provide = msmFreeProvide(provide));
+    msmFreePointer((void**)&package->name);
+    msmFreePointer((void**)&package->modified);
+    msmFreePointer((void**)&package);
+    return prev;
+}
+
+static keyinfo_x *msmFreeKeyinfo(keyinfo_x *keyinfo)
+{
+    keyinfo_x *prev = keyinfo->prev;
+    msmFreePointer((void**)&keyinfo->keydata);
+    msmFreePointer((void**)&keyinfo);
+    return prev;
+}
+
+static access_x *msmFreeAccess(access_x *access)
+{
+    access_x *prev = access->prev;
+    msmFreePointer((void**)&access->data);
+    msmFreePointer((void**)&access->type);
+    msmFreePointer((void**)&access);
+    return prev;
+}
+
+static origin_x *msmFreeOrigin(origin_x *origin)
+{
+    keyinfo_x *keyinfo;
+    access_x *access;
+    origin_x *prev = origin->prev;
+    for (keyinfo = origin->keyinfos; keyinfo; keyinfo = msmFreeKeyinfo(keyinfo));
+    for (access = origin->accesses; access; access = msmFreeAccess(access));
+    msmFreePointer((void**)&origin->type);
+    msmFreePointer((void**)&origin);
+    return prev;
+}
+
+static sw_source_x *msmFreeSWSource(sw_source_x *sw_source)
+{
+    package_x *package;
+    ac_domain_x *ac_domain, *temp;
+    origin_x *origin;
+    sw_source_x *next = sw_source->next;
+
+    rpmlog(RPMLOG_DEBUG, "freeing sw source %s\n", sw_source->name);
+
+    for (package = sw_source->packages; package; package = msmFreePackage(package));
+    for (ac_domain = sw_source->allowmatches; ac_domain; ac_domain = msmFreeACDomain(ac_domain));
+    if (sw_source->allows) {
+       HASH_ITER(hh, sw_source->allows, ac_domain, temp) {
+           HASH_DELETE(hh, sw_source->allows, ac_domain);
+           msmFreeACDomain(ac_domain);
+       }
+    }
+
+    for (ac_domain = sw_source->denymatches; ac_domain; ac_domain = msmFreeACDomain(ac_domain));
+    if (sw_source->denys) {
+       HASH_ITER(hh, sw_source->denys, ac_domain, temp) {
+           HASH_DELETE(hh, sw_source->denys, ac_domain);
+           msmFreeACDomain(ac_domain);
+       }
+    }
+    for (origin = sw_source->origins; origin; origin = msmFreeOrigin(origin));
+    msmFreePointer((void**)&sw_source->name);
+    msmFreePointer((void**)&sw_source->rankkey);
+    msmFreePointer((void**)&sw_source);
+    return next;
+}
+
+static d_request_x *msmFreeDRequest(d_request_x *d_request)
+{
+    d_request_x *next = d_request->next;
+    rpmlog(RPMLOG_DEBUG, "freeing domain request %s\n", d_request->label_name);
+    msmFreePointer((void**)&d_request->label_name);
+    msmFreePointer((void**)&d_request->ac_type);
+    msmFreePointer((void**)&d_request);
+    return next;
+}
+
+static d_permit_x *msmFreeDPermit(d_permit_x *d_permit)
+{
+    d_permit_x *next = d_permit->next;
+    rpmlog(RPMLOG_DEBUG, "freeing domain permit %s\n", d_permit->label_name);
+    msmFreePointer((void**)&d_permit->label_name);
+    msmFreePointer((void**)&d_permit->to_label_name);
+    msmFreePointer((void**)&d_permit->ac_type);
+    msmFreePointer((void**)&d_permit);
+    return next;
+}
+
+static d_provide_x *msmFreeDProvide(d_provide_x *d_provide)
+{
+    d_provide_x *next = d_provide->next;
+    rpmlog(RPMLOG_DEBUG, "freeing domain provide %s\n", d_provide->label_name);
+    msmFreePointer((void**)&d_provide->label_name);
+    msmFreePointer((void**)&d_provide);
+    return next;
+}
+
+manifest_x* msmFreeManifestXml(manifest_x* mfx)
+{
+    provide_x *provide;
+    file_x *file;
+    sw_source_x *sw_source;
+    d_request_x *d_request;
+    d_permit_x *d_permit;
+    d_provide_x *d_provide;
+
+    rpmlog(RPMLOG_DEBUG, "in msmFreeManifestXml\n");
+    if (mfx) {
+       if (mfx->provides)
+               for (provide = mfx->provides; provide; provide = msmFreeProvide(provide));
+       rpmlog(RPMLOG_DEBUG, "after freeing provides\n");
+       if (mfx->request) {
+               msmFreePointer((void**)&mfx->request->ac_domain);
+               msmFreePointer((void**)&mfx->request);
+       }
+       rpmlog(RPMLOG_DEBUG, "after freeing requests\n");
+       for (file = mfx->files; file; file = msmFreeFile(file));
+       rpmlog(RPMLOG_DEBUG, "after freeing files\n");
+       if (mfx->sw_sources) {
+           LISTHEAD(mfx->sw_sources, sw_source);       
+           for (; sw_source; sw_source = msmFreeSWSource(sw_source));
+       }
+       msmFreePointer((void**)&mfx->name);
+       rpmlog(RPMLOG_DEBUG, "after freeing name\n");
+       if (mfx->define) {
+               msmFreePointer((void**)&mfx->define->name);
+               msmFreePointer((void**)&mfx->define->policy);
+               msmFreePointer((void**)&mfx->define->plist);
+               if (mfx->define->d_requests) {
+                       LISTHEAD(mfx->define->d_requests, d_request);   
+                       for (; d_request; d_request = msmFreeDRequest(d_request));
+               }
+               rpmlog(RPMLOG_DEBUG, "after freeing define requests\n");
+               if (mfx->define->d_permits) {
+                       LISTHEAD(mfx->define->d_permits, d_permit);     
+                       for (; d_permit; d_permit = msmFreeDPermit(d_permit));
+               }
+               rpmlog(RPMLOG_DEBUG, "after freeing define permits\n");
+               if (mfx->define->d_provides) {
+                       LISTHEAD(mfx->define->d_provides, d_provide);   
+                       for (; d_provide; d_provide = msmFreeDProvide(d_provide));
+               }
+               rpmlog(RPMLOG_DEBUG, "after freeing provides\n");
+               msmFreePointer((void**)&mfx->define); 
+       }
+
+       rpmlog(RPMLOG_DEBUG, "after freeing defines \n");
+       msmFreePointer((void**)&mfx);
+    }
+    return mfx; 
+}
+
+manifest_x *msmProcessManifestXml(const char *buffer, int size, sw_source_x *current, const char *packagename) 
+{
+    xmlTextReaderPtr reader;
+    manifest_x *mfx = NULL;
+
+    reader = xmlReaderForMemory(buffer, size, NULL, NULL, 0);
+
+    if (reader) {
+       mfx = calloc(1, sizeof(manifest_x));
+       if (mfx) {
+           mfx->name = strdup(packagename);
+           if (msmProcessManifest(reader, mfx, current) < 0) {
+           /* error in parcing. Let's display some hint where we failed */
+               rpmlog(RPMLOG_DEBUG, "Syntax error in processing manifest in the above line\n");
+               mfx = msmFreeManifestXml(mfx);
+           }
+       }
+       xmlFreeTextReader(reader);
+    } else {
+        rpmlog(RPMLOG_ERR, "Unable to create xml reader\n");
+    }
+    return mfx;
+}
+
+manifest_x *msmProcessDevSecPolicyXml(const char *filename) 
+{
+    xmlTextReaderPtr reader;
+    manifest_x *mfx = NULL;
+
+    reader = xmlReaderForFile(filename, NULL, 0);
+
+    if (reader) {
+       mfx = calloc(1, sizeof(manifest_x));
+       if (mfx) {
+           if (msmProcessManifest(reader, mfx, NULL) < 0) {
+               mfx = msmFreeManifestXml(mfx);
+           }
+       }
+        xmlFreeTextReader(reader);
+    } else {
+        rpmlog(RPMLOG_ERR, "Unable to open device security policy %s\n", filename);
+    }
+    return mfx;
+}
diff --git a/plugins/msmmatch.c b/plugins/msmmatch.c
new file mode 100644 (file)
index 0000000..0fcf8b9
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * This file is part of MSM security plugin
+ * Greatly based on the code of MSSF security plugin
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Tero Aho <ext-tero.aho@nokia.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; either version 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "msm.h"
+
+/* Wild card strcmp, wild cards * and ? allowed in s1 */
+int strwcmp(const char *s1, const char *s2)
+{
+    char *c1 = (char *)s1;
+    char *c2 = (char *)s2;
+    char *star = NULL;
+    int ok = 0;
+
+    if (!s1 || !s2) return 1;
+
+    while (*c2) {
+       if (*c1 == '*') {
+           if (star && (c1 - star) != ok)
+               goto fail;
+           c1++;
+           star = c1;
+           ok = 0;
+       }
+       if (*c1 == '?') {
+           c1++;
+           c2++;
+           continue;
+       }           
+       if (*c1 == *c2) {
+           c1++;
+           c2++;
+           ok++;
+       } else if (star) {
+           c1 = star;
+           c2++;
+           ok = 0;
+       } else goto fail;
+    }
+    if (*c1 == '\0' && *c2 == '\0' && (!star || (c1 - star) == ok))
+       return 0;
+ fail:
+    return (*c1 < *c2 ? -1 : 1);
+}
+
diff --git a/plugins/msmxattr.c b/plugins/msmxattr.c
new file mode 100644 (file)
index 0000000..4db937e
--- /dev/null
@@ -0,0 +1,1327 @@
+/*
+ * This file is part of MSM security plugin
+ * Greatly based on the code of MSSF security plugin
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Tero Aho <ext-tero.aho@nokia.com>
+ *
+ * Copyright (C) 2011 - 2013 Intel Corporation.
+ *
+ * Contact: Elena Reshetova <elena.reshetova@intel.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; either version 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/capability.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <attr/xattr.h>
+#include <uthash.h>
+#include <magic.h>
+#include "rpmio/rpmlog.h"
+#include "rpm/rpmlib.h"
+#include <rpm/rpmmacro.h>
+#include <rpm/rpmts.h>
+
+#include "msm.h"
+
+static ac_domain_x *all_ac_domains = NULL; /* hash of all provided ac domains */
+static package_x *allpackages = NULL; /* hash of all installed packages */
+
+void msmFreeInternalHashes(void)
+{
+    if (all_ac_domains) {
+       HASH_CLEAR(hh,all_ac_domains);
+    }
+
+    if (allpackages) {
+       HASH_CLEAR(hh,allpackages);
+    }
+}
+
+static int msmCheckACDomainRules(ac_domain_x *ac_domain, 
+                                   sw_source_x *requested, sw_source_x *provided)
+{
+    sw_source_x *sw_source;
+
+    /* go through sw source and its parents: ac domains must not match */
+    /* deny or deny wildcards and must match allow or allow wildcards */
+    /* in the whole path up to the level of the providing sw source */ 
+
+    for (sw_source = requested; sw_source->parent && sw_source->parent != sw_source; sw_source = sw_source->parent) {
+       ac_domain_x *denied;
+       ac_domain_x *allowed;
+       /* check first if requested ac domain is denied */
+       HASH_FIND(hh, sw_source->denys, ac_domain->name, strlen(ac_domain->name), denied);
+       if (denied) return 0; /* matched deny */
+       for (denied = sw_source->denymatches; denied; denied = denied->prev)
+           if (!strwcmp(denied->match, ac_domain->name)) 
+               return 0; /* matched deny wildcard */
+
+       /* not denied, now check if it's in allows or allowmatches */
+       HASH_FIND(hh, sw_source->allows, ac_domain->name, strlen(ac_domain->name), allowed);
+       if (allowed) continue; /* matched allow */
+       for (allowed = sw_source->allowmatches; allowed; allowed = allowed->prev)
+           if (!strwcmp(allowed->match, ac_domain->name)) 
+               break; /* matched allow wildcard */
+       if (allowed) continue; /* matched allow wildcard */
+
+       if (strcmp(sw_source->rankkey, provided->rankkey) <= 0)
+           return 1; /* ranked higher (or same sw source), allow */
+       return 0; /* not mentioned, deny */
+    }
+    return 1; /* still here, allow for root sw source */
+}
+
+static int msmCheckLabelProvisioning(manifest_x *mfx, const char* label) 
+{
+
+    d_provide_x *provide = NULL;
+
+    if ((mfx) && (label) && (mfx->define) && (mfx->define->d_provides)) {
+           for (provide = mfx->define->d_provides; provide; provide = provide->prev) {
+               if ( strcmp(provide->label_name, label) == 0 )
+                       return 0;
+           }
+    }
+    rpmlog(RPMLOG_ERR, "Label %s hasn't been provided in the manifest\n", label);
+    return -1;
+}
+
+static int msmSetSmackRules(struct smack_accesses *smack_accesses, ac_domain_x *ac_domains, const char *aid)
+{
+    ac_domain_x *ac_domain;
+    int ret = 0;
+
+    if (!smack_accesses) return ret;
+
+    for (ac_domain = ac_domains; ac_domain; ac_domain = ac_domain->prev) {
+       if (ac_domain->allowed) {
+           ret = smack_accesses_add(smack_accesses, aid, ac_domain->name, "rw");
+           if (ret < 0) {
+               rpmlog(RPMLOG_ERR, "smack_add failed for %s %s\n", 
+                      aid, ac_domain->name);
+               return ret;
+           }
+       }/* else if (!ac_domain->allowed && !ac_domain->newer) {
+           // remove not allowed rule in case something has changed 
+           smack_rule_set_remove(rule_set, aid, ac_domain->name, NULL);
+       }*/
+    }
+    return ret;
+
+}
+
+static int msmIsProvideAllowed(ac_domain_x *provided, sw_source_x *sw_source, const char *origin)
+{
+
+    /* first check provided ac_domain attributes */
+    if (provided->sw_source == sw_source) {
+       /* allowed always if ac_domain is provided in the same sw source */
+       return 1;
+    } else if (origin && !strcmp(origin, "current")) {
+       /* denied if ac_domain is only meant for current sw source */
+       return 0;
+    }
+    if (origin && !strcmp(origin, "all")) {
+       /* ac_domain is allowed for all sw sources */
+       return 1;
+    }
+    if (!origin || !strcmp(origin, "trusted")) {
+       if (strcmp(sw_source->rankkey, provided->sw_source->rankkey) < 0) {
+           /* higher ranked sw sources are allowed if ac_domain is trusted */
+           return 1;
+       } /* else flow through to check denys and allows below */
+    } else return 0;
+
+    return msmCheckACDomainRules(provided, sw_source, provided->sw_source);
+}
+
+static int msmSetSmackProvide(struct smack_accesses *smack_accesses, provide_x *provide, sw_source_x *sw_source)
+{
+    ac_domain_x *ac_domain;
+    sw_source_x *current = sw_source;
+    int ret = -1;
+
+    if (!provide || (!provide->ac_domains)) return 0;
+
+    /* set smack rules for all sw sources */
+    LISTHEAD(current, sw_source);
+    for (; sw_source; sw_source = sw_source->next) {
+       if (!sw_source->newer) {
+           for (ac_domain = provide->ac_domains; ac_domain; ac_domain = ac_domain->prev) {
+                   ac_domain->allowed = msmIsProvideAllowed(ac_domain, sw_source, ac_domain->origin);
+                   rpmlog(RPMLOG_INFO, "%s ac_domain %s provided in %s for %s\n", (ac_domain->allowed ? "allowing" : "not allowing"), 
+                                                       ac_domain->name, ac_domain->sw_source->name, sw_source->name);
+           }
+           if (smack_accesses)
+               ret = msmSetSmackRules(smack_accesses, provide->ac_domains, sw_source->name);
+           else 
+               ret = 0;
+       }
+    }
+    return ret;
+}
+
+static int msmSetupZypperRepo(access_x *access, sw_source_x *sw_source)
+{
+    struct stat sb;
+    char path[FILENAME_MAX+1];
+    FILE *file = NULL;
+    char data[512];
+    int ret = -1;
+
+    /* NOTE: Creating zypper repos manually here! */
+    /* A library call would be the correct way, but calling c++ from c */
+    /* is not nice. On the other hand, now there is no libzypp dependency. */
+
+    char *sysconfdir = rpmExpand("%{?_sysconfdir}", NULL);
+    if (!sysconfdir || !strcmp(sysconfdir, "")) {
+       rpmlog(RPMLOG_ERR, "Failed to expand %%_sysconfdir macro\n");
+       goto exit;
+    }
+    snprintf(path, sizeof(path), "%s/zypp", sysconfdir);
+    if (stat(path, &sb) == -1) {
+       rpmlog(RPMLOG_ERR, "Failed to stat %s: %s\n", 
+              path, strerror(errno));
+       goto exit;
+    }
+    snprintf(path, sizeof(path), "%s/zypp/repos.d", sysconfdir);
+    if (stat(path, &sb) == -1) {
+       if (mkdir(path, 0755) == -1) {
+           rpmlog(RPMLOG_ERR, "Failed to create %s: %s\n", 
+                  path, strerror(errno));
+           goto exit;
+       }
+    }
+    snprintf(path, sizeof(path), "%s/zypp/repos.d/%s.repo", 
+            sysconfdir, sw_source->name);
+    file = fopen(path, "w");
+    if (!file) {
+       rpmlog(RPMLOG_ERR, "Failed to open %s: %s\n", 
+              path, strerror(errno));
+       goto exit;
+    }
+    snprintf(data, sizeof(data), 
+            "[%s]\n"
+            "name=%s\n"
+            "enabled=1\n"
+            "autorefresh=0\n"
+            "baseurl=%s\n"
+            "type=%s\n"
+            "keeppackages=0\n", 
+            sw_source->name, sw_source->name, access->data, 
+            (access->type ? access->type : "NONE"));
+
+    if (fputs(data, file) == EOF) {
+       rpmlog(RPMLOG_ERR, "Failed to write %s: %s\n", 
+              path, strerror(errno));
+       goto exit;
+    }
+    rpmlog(RPMLOG_INFO, "added zypper repository %s for sw source %s\n", 
+          path, sw_source->name);
+
+    ret = 0;
+ exit:
+    if (file) fclose(file);
+    msmFreePointer((void**)&sysconfdir);
+
+    return ret;
+}
+
+static int msmSetSmackSWSource(struct smack_accesses *smack_accesses, sw_source_x *sw_source)
+{
+    package_x *package, *temp;
+    provide_x *provide;
+
+    if (!allpackages) return 0;
+
+    if (sw_source->older) {
+       ac_domain_x *ac_domain, *temp;
+       /* remove old domain rules in case of upgrade */
+       //smack_rule_set_remove_by_subject(rule_set, sw_source->name, NULL);
+       /* make sure domain's credentials point to upgraded domain */
+       HASH_ITER(hh, all_ac_domains, ac_domain, temp) {
+           if (ac_domain->sw_source == sw_source->older)
+               ac_domain->sw_source = sw_source;
+       }
+    }
+
+    /* iterate through all packages to create smack rules for the domain */
+    HASH_ITER(hh, allpackages, package, temp) {
+       if (sw_source->older) {
+           /* make sure domain's packages point to upgraded domain */
+           if (package->sw_source == sw_source->older)
+               package->sw_source = sw_source;
+       }
+       if (!package->newer) {
+           for (provide = package->provides; provide; provide = provide->prev) {
+               if (msmSetSmackProvide(smack_accesses, provide, package->sw_source))
+                   return -1;
+           }
+       }
+    }
+    return 0;
+}
+
+int msmSetupSWSources(struct smack_accesses *smack_accesses, manifest_x *mfx, rpmts ts) 
+{
+    sw_source_x *sw_source;
+    origin_x *origin;
+    keyinfo_x *keyinfo;
+    access_x *access;
+    ac_domain_x *allow;
+    ac_domain_x *deny;
+    ac_domain_x *ac_domain;
+    int ret;
+    rpmRC rc;
+
+    LISTHEAD(mfx->sw_sources, sw_source);
+
+    while (sw_source) {
+       sw_source_x *next = sw_source->next;
+       sw_source_x *parent = sw_source->parent;
+       if (ts) {
+           for (origin = sw_source->origins; origin; origin = origin->prev) {
+               for (keyinfo = origin->keyinfos; keyinfo; keyinfo = keyinfo->prev) {
+                   rpmlog(RPMLOG_INFO, "setting keyinfo for sw source %s\n", 
+                          sw_source->name);
+                   rc = rpmtsImportPubkey(ts, keyinfo->keydata, keyinfo->keylen);
+                   if (rc != RPMRC_OK) {
+                       rpmlog(RPMLOG_ERR, "Key import failed for sw source %s\n",
+                              sw_source->name);
+                       return rc;
+                   }
+               }
+               for (access = origin->accesses; access; access = access->prev) {
+                   rpmlog(RPMLOG_INFO, "setting access %s for sw source %s\n", 
+                          access->data, sw_source->name);
+                   if (origin->type && !strcmp(origin->type, "ZYPPER")) {
+                       ret = msmSetupZypperRepo(access, sw_source);
+                       if (ret) {
+                           rpmlog(RPMLOG_ERR, 
+                                  "Failed to set access %s for sw source %s\n",
+                                  access->data, sw_source->name);
+                           return ret;
+                       }
+                   }
+               }
+           }
+       } else {
+
+           /* config processing */
+           ret = msmSetupPackages(NULL, sw_source->packages, NULL);
+           if (ret) {
+               rpmlog(RPMLOG_ERR, "Setup packages failed for sw source %s\n",
+                      sw_source->name);
+               return ret;
+           }
+       }
+       if (ts) {
+           for (allow = sw_source->allows; allow; allow = allow->hh.next) {
+               HASH_FIND(hh, all_ac_domains, allow->name, strlen(allow->name), ac_domain);
+               if (ac_domain) {
+                   rpmlog(RPMLOG_INFO, "sw source %s allows access to ac domain %s\n", 
+                          sw_source->name, allow->name);
+               } else {
+                   rpmlog(RPMLOG_WARNING, "sw source %s allows access to ac domain %s which doesn't exist\n", 
+                          sw_source->name, allow->name);
+               }
+           }
+           for (allow = sw_source->allowmatches; allow; allow = allow->prev)
+               rpmlog(RPMLOG_INFO, "sw source %s allows access to ac domain match %s\n", 
+                      sw_source->name, allow->match);
+
+           for (deny = sw_source->denys; deny; deny = deny->hh.next) {
+               HASH_FIND(hh, all_ac_domains, deny->name, strlen(deny->name), ac_domain);
+               if (ac_domain) {
+                   rpmlog(RPMLOG_INFO, "sw source %s denies access to ac domain %s\n", 
+                          sw_source->name, deny->name);
+               } else {
+                   rpmlog(RPMLOG_WARNING, "sw source %s denies access to ac domain %s which doesn't exist\n", 
+                          sw_source->name, deny->name);
+               }
+           }
+           for (deny = sw_source->denymatches; deny; deny = deny->prev)
+               rpmlog(RPMLOG_INFO, "sw source %s denies access to ac domain match %s\n", 
+                      sw_source->name, deny->match);
+
+           if (parent) {
+               if (strcmp(parent->name, sw_source->name)) {
+                   sw_source_x *older;
+                   for (older = parent; older; older = older->next) {
+                       if (!strcmp(sw_source->name, older->name)) {
+                           sw_source->older = older;
+                           older->newer = sw_source;
+                           break;
+                       }
+                   }
+               } else if (!parent->parent) {
+                   /* root sw_source upgrade */
+                   sw_source->older = parent;
+                   parent->newer = sw_source;
+                   sw_source->parent = NULL;
+               } else return -1;
+
+               LISTDEL(mfx->sw_sources, sw_source); /* take out from sw sources list */
+               NODEADD(parent, sw_source); /* add to sw source tree */
+           }
+
+           /* set smack rules for the new/upgraded sw source */
+           ret = msmSetSmackSWSource(smack_accesses, sw_source);
+           if (ret) {
+               rpmlog(RPMLOG_ERR, "Setting smack rules failed for sw source %s\n",
+                      sw_source->name);
+               return ret;
+           }
+
+       }
+       sw_source = next;
+    }
+    return 0;
+}
+
+static void msmRemoveDBusConfig(package_x *package, dbus_x *dbuss)
+{
+    dbus_x *dbus;
+
+    for (dbus = dbuss; dbus; dbus = dbus->prev) {
+       char path[FILENAME_MAX+1];
+       snprintf(path, sizeof(path), "/etc/dbus-1/%s.d/manifest.%s.conf", 
+                dbus->bus, package->name);
+       unlink(path);
+    }
+}
+
+static int msmSetupDBusRule(FILE *file, const char *creds, int type, const char *service, const char *name, const char *parentType, const char *parentValue)
+{
+    char data[1024];
+
+    if (creds && *creds) {
+       switch (type) {
+       case DBUS_SERVICE:
+           snprintf(data, sizeof(data), 
+                    "  <policy context=\"default\">\n"
+                    "    <deny send_destination=\"%s\"/>\n"
+                    "  </policy>\n"
+                    "  <policy smack=\"%s\">\n"
+                    "    <allow send_destination=\"%s\"/>\n"
+                    "  </policy>\n",
+                    name, creds, name);
+           break;
+       case DBUS_PATH:
+           snprintf(data, sizeof(data), 
+                    "  <policy context=\"default\">\n"
+                    "    <deny send_destination=\"%s\" send_path=\"%s\"/>\n"
+                    "    <deny receive_sender=\"%s\" receive_path=\"%s\"/>\n"
+                    "  </policy>\n"
+                    "  <policy smack=\"%s\">\n"
+                    "    <allow send_destination=\"%s\" send_path=\"%s\"/>\n"
+                    "    <allow receive_sender=\"%s\" receive_path=\"%s\"/>\n"
+                    "  </policy>\n",
+                    service, name, service, name, creds,
+                    service, name, service, name);
+           break;
+       case DBUS_INTERFACE:
+           snprintf(data, sizeof(data), 
+                    "  <policy context=\"default\">\n"
+                    "    <deny send_destination=\"%s\" send_interface=\"%s\"/>\n"
+                    "    <deny receive_sender=\"%s\" receive_interface=\"%s\"/>\n"
+                    "  </policy>\n"
+                    "  <policy smack=\"%s\">\n"
+                    "    <allow send_destination=\"%s\" send_interface=\"%s\"/>\n"
+                    "    <allow receive_sender=\"%s\" receive_interface=\"%s\"/>\n"
+                    "  </policy>\n",
+                    service, name, service, name, creds,
+                    service, name, service, name);
+           break;
+       case DBUS_METHOD:
+           snprintf(data, sizeof(data), 
+                    "  <policy context=\"default\">\n"
+                    "    <deny send_destination=\"%s\" send_%s=\"%s\" send_member=\"%s\"/>\n"
+                    "  </policy>\n"
+                    "  <policy smack=\"%s\">\n"
+                    "    <allow send_destination=\"%s\" send_%s=\"%s\" send_member=\"%s\"/>\n"
+                    "  </policy>\n",
+                    service, parentType, parentValue, name, creds,
+                    service, parentType, parentValue, name);
+           break;
+       case DBUS_SIGNAL:
+           snprintf(data, sizeof(data), 
+                    "  <policy context=\"default\">\n"
+                    "    <deny receive_sender=\"%s\" receive_%s=\"%s\" receive_member=\"%s\"/>\n"
+                    "  </policy>\n"
+                    "  <policy smack=\"%s\">\n"
+                    "    <allow receive_sender=\"%s\" receive_%s=\"%s\" receive_member=\"%s\"/>\n"
+                    "  </policy>\n",
+                    service, parentType, parentValue, name, creds,
+                    service, parentType, parentValue, name);
+           break;
+       default:
+           return -1;
+       }
+    } else {
+       switch (type) {
+       case DBUS_SERVICE:
+           snprintf(data, sizeof(data), 
+                    "  <policy context=\"default\">\n"
+                    "    <allow send_destination=\"%s\"/>\n"
+                    "  </policy>\n",
+                    name);
+           break;
+       case DBUS_PATH:
+           snprintf(data, sizeof(data), 
+                    "  <policy context=\"default\">\n"
+                    "    <allow send_destination=\"%s\" send_path=\"%s\"/>\n"
+                    "    <allow receive_sender=\"%s\" receive_path=\"%s\"/>\n"
+                    "  </policy>\n",
+                    service, name, service, name);
+           break;
+       case DBUS_INTERFACE:
+           snprintf(data, sizeof(data), 
+                    "  <policy context=\"default\">\n"
+                    "    <allow send_destination=\"%s\" send_interface=\"%s\"/>\n"
+                    "    <allow receive_sender=\"%s\" receive_interface=\"%s\"/>\n"
+                    "  </policy>\n",
+                    service, name, service, name);
+           break;
+       case DBUS_METHOD:
+           snprintf(data, sizeof(data), 
+                    "  <policy context=\"default\">\n"
+                    "    <allow send_destination=\"%s\" send_%s=\"%s\" send_member=\"%s\"/>\n"
+                    "  </policy>\n",
+                    service, parentType, parentValue, name);
+           break;
+       case DBUS_SIGNAL:
+           snprintf(data, sizeof(data), 
+                    "  <policy context=\"default\">\n"
+                    "    <allow receive_sender=\"%s\" receive_%s=\"%s\" receive_member=\"%s\"/>\n"
+                    "  </policy>\n",
+                    service, parentType, parentValue, name);
+           break;
+       default:
+           return -1;
+       }
+    }
+    if (fputs(data, file) == EOF) {
+       rpmlog(RPMLOG_ERR, "Failed to write DBus rule %s: %s\n", 
+              data, strerror(errno));
+       return -1;
+    }
+    return 0;
+}
+
+static int msmSetupDBusConfig(package_x *package, dbus_x *dbus, int phase)
+{
+    char path[FILENAME_MAX+1];
+    FILE *file = NULL;
+    char data[512];
+    node_x *node;
+    interface_x *interface;
+    member_x *member;
+    int ret = -1;
+
+    char *sysconfdir = rpmExpand("%{?_sysconfdir}", NULL);
+    if (!sysconfdir || !strcmp(sysconfdir, "")) {
+       rpmlog(RPMLOG_ERR, "Failed to expand %%_sysconfdir macro\n");
+       goto exit;
+    }
+    snprintf(path, sizeof(path), "%s/dbus-1/%s.d/manifest.%s.conf", 
+            sysconfdir, dbus->bus, package->name);
+
+    file = fopen(path, phase ? "a" : "w");
+    if (!file) {
+       rpmlog(RPMLOG_ERR, "Cannot open %s: %s\n", path, strerror(errno));
+       goto exit;
+    }
+
+    if (phase == 0) {
+       snprintf(data, sizeof(data), 
+                "<!-- This configuration is automatically generated from Manifest by RPM %s security plugin -->\n"
+                "<!DOCTYPE busconfig PUBLIC \"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN\" \"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd\">\n"
+                "<busconfig>\n",
+                rpmEVR);
+       if (fputs(data, file) == EOF) {
+           rpmlog(RPMLOG_ERR, "Failed to write %s: %s\n", 
+                  path, strerror(errno));
+           goto exit;
+       }
+    }
+
+    if (phase >= 0) {
+       if (dbus->own) {
+               snprintf(data, sizeof(data), 
+                        "  <policy context=\"default\">\n"
+                        "    <deny own=\"%s\"/>\n"
+                        "  </policy>\n"
+                        "  <policy smack=\"%s\">\n"
+                        "    <allow own=\"%s\"/>\n"
+                        "  </policy>\n",
+                        dbus->name, dbus->own, dbus->name);
+               if (fputs(data, file) == EOF) {
+                   rpmlog(RPMLOG_ERR, "Failed to write %s: %s\n", 
+                          path, strerror(errno));
+                   goto exit;
+               }
+       }
+       if (dbus->annotation) {
+               msmSetupDBusRule(file, dbus->annotation->value, DBUS_SERVICE, 
+                                 NULL, dbus->name, NULL, NULL);
+       }
+       for (node = dbus->nodes; node; node = node->prev) {
+           if (node->annotation) {
+                   msmSetupDBusRule(file, node->annotation->value, DBUS_PATH,
+                                     dbus->name, node->name, NULL, NULL);
+           }
+           for (member = node->members; member; member = member->prev) {
+               if (member->annotation) {
+                       msmSetupDBusRule(file, member->annotation->value, member->type, 
+                                         dbus->name, member->name, 
+                                         "path", node->name);
+               }
+           }
+           for (interface = node->interfaces; interface; interface = interface->prev) {
+               if (interface->annotation) {
+                       msmSetupDBusRule(file, interface->annotation->value, DBUS_INTERFACE, 
+                                         dbus->name, interface->name, NULL, NULL);
+               }
+               for (member = interface->members; member; member = member->prev) {
+                   if (member->annotation) {
+                           msmSetupDBusRule(file, member->annotation->value, member->type, 
+                                             dbus->name, member->name,
+                                             "interface", interface->name);
+                   }
+               }
+           }
+       }
+    }
+
+    if (phase < 0) {
+       snprintf(data, sizeof(data), "</busconfig>\n");
+       if (fputs(data, file) == EOF) {
+           rpmlog(RPMLOG_ERR, "Failed to write %s: %s\n", 
+                  path, strerror(errno));
+           goto exit;
+       }
+       rpmlog(RPMLOG_INFO, "wrote dbus config %s\n", path);    
+    }
+    ret = 0;
+
+ exit:
+    if (file) fclose(file);
+    if (ret) unlink(path);
+    msmFreePointer((void**)&sysconfdir);
+
+    return ret;
+}
+
+static int msmIsRequestAllowed(manifest_x *mfx, ac_domain_x *provided)
+{
+  
+    if (mfx->sw_source == provided->sw_source) {
+       /* allowed always if ac domain is provided in the same sw source */
+       return 1;
+    } else if (provided->origin && !strcmp(provided->origin, "current")) {
+       /* denied if ac domain is only meant for current sw source */
+       return 0;
+    }
+    if (provided->origin && !strcmp(provided->origin, "all")) {
+       /* ac_domain is allowed for all sw sources */
+       return 1;
+    }
+    if (!provided->origin || !strcmp(provided->origin, "trusted")) {
+       if (strcmp(mfx->sw_source->rankkey, provided->sw_source->rankkey) < 0) {
+           /* higher ranked sw sources are allowed if ac domain is trusted */
+           return 1;
+       } /* else flow through to check denys and allows below */
+    } else return 0;
+
+    return msmCheckACDomainRules(provided, mfx->sw_source, provided->sw_source);
+}
+
+static int msmCheckDomainJoinPossibility(manifest_x *mfx, ac_domain_x *defined_ac_domain) 
+{
+
+    char *tmp = NULL, *pch = NULL;
+    unsigned int found = 0;
+
+    if ((!mfx) || (!defined_ac_domain))
+       return -1; 
+
+    if (defined_ac_domain->type) {
+       if (strcmp(defined_ac_domain->type, "restricted") == 0) {
+               if (defined_ac_domain->plist) {
+                       tmp = calloc(strlen(defined_ac_domain->plist) + 1, sizeof(char));
+                       if (!tmp) return -1; 
+                       strncpy(tmp, defined_ac_domain->plist, strlen(defined_ac_domain->plist));
+                       pch = strtok (tmp, ", ");
+                       while (pch != NULL)
+                       {
+                               if (strcmp(pch, mfx->name) == 0) {
+                                       found = 1; 
+                                       break;
+                               }                                       
+                               pch = strtok(NULL, ", ");
+                       }
+                       msmFreePointer((void**)&tmp);
+               }
+               if (found != 1) {
+                       rpmlog(RPMLOG_ERR, "Request for a domain name %s isn't allowed ", mfx->request->ac_domain);
+                       rpmlog(RPMLOG_ERR, "because ac domain is marked as restricted\n");
+                       return -1;
+               }
+       } else if (strcmp(defined_ac_domain->type, "shared") == 0) {
+               return 0;                       
+       } else {
+               // domain hasn't been marked as shared 
+               rpmlog(RPMLOG_ERR, "Request for a domain name %s isn't allowed ", mfx->request->ac_domain);
+               rpmlog(RPMLOG_ERR, "because ac domain is marked as private\n");
+               return -1;
+       }
+   } else { 
+       // by default ac domains are private
+       rpmlog(RPMLOG_ERR, "Request for a domain name %s isn't allowed ", mfx->request->ac_domain);
+       rpmlog(RPMLOG_ERR, "because ac domain is marked as private\n");
+       return -1;
+  }
+
+  return 0;
+}
+
+int msmSetupRequests(manifest_x *mfx) 
+{
+
+       ac_domain_x *defined_ac_domain = NULL; 
+
+       if ((!mfx) || (!mfx->request) || (!mfx->request->ac_domain))
+               return -1;
+       
+       HASH_FIND(hh, all_ac_domains, mfx->request->ac_domain, strlen(mfx->request->ac_domain), defined_ac_domain);
+       if (!defined_ac_domain){ // request for a undefined domain. 
+               rpmlog(RPMLOG_ERR, "Request for a domain name %s that hasn't been yet defined by any package\n", mfx->request->ac_domain);
+               return -1;
+       }
+
+       //now check that the package can join the requested AC domain
+
+       if (mfx->define){
+               rpmlog(RPMLOG_DEBUG, "mfx->define->name %s mfx->request->ac_domain %s\n", mfx->define->name, mfx->request->ac_domain);
+               if (strcmp(mfx->define->name, mfx->request->ac_domain) == 0)
+                       //ac domain is requested from the same package where it was define. This case is always allowed
+                       return 0;               
+       } 
+
+       //need to check if developer allowed other packages to join this domain
+       if (msmCheckDomainJoinPossibility(mfx, defined_ac_domain) < 0 )
+               return -1;
+       
+       // now checking if security policy allows to join this domain
+       if (msmIsRequestAllowed(mfx, defined_ac_domain)) {
+           rpmlog(RPMLOG_INFO, "Request for a domain name %s is allowed based on package sw source\n", mfx->request->ac_domain);
+           return 0;
+               
+       } else {
+           rpmlog(RPMLOG_ERR, "Request for a domain name %s isn't allowed based on package sw source\n", mfx->request->ac_domain);
+           return -1;
+       }
+}
+
+static int msmSetupProvides(struct smack_accesses *smack_accesses, package_x *package)
+{
+    provide_x *provide;
+    ac_domain_x *ac_domain;
+
+    for (provide = package->provides; provide; provide = provide->prev) {
+       for (ac_domain = provide->ac_domains; ac_domain; ac_domain = ac_domain->prev) {
+           ac_domain_x *current_d = NULL;
+           ac_domain->origin = provide->origin;
+
+           HASH_FIND(hh, all_ac_domains, ac_domain->name, strlen(ac_domain->name), current_d);
+
+           if (current_d) { /* ac domain has been previously defined */
+
+               if (strcmp(ac_domain->pkg_name, current_d->pkg_name) == 0) { /* check that it was provided by same package */           
+                       HASH_DELETE(hh, all_ac_domains, current_d);
+                       HASH_ADD_KEYPTR(hh, all_ac_domains, ac_domain->name, strlen(ac_domain->name), ac_domain);
+                       current_d->newer = ac_domain;
+                       ac_domain->older = current_d;
+                       rpmlog(RPMLOG_INFO, "package %s upgraded ac domain %s\n", ac_domain->pkg_name, ac_domain->name);
+                 
+               } else {
+                   rpmlog(RPMLOG_ERR, "package %s can't upgrade ac domain %s previously defined in package %s\n", 
+                                                                       ac_domain->pkg_name, ac_domain->name, current_d->pkg_name);
+                   return -1;
+               }
+           } else {
+               HASH_ADD_KEYPTR(hh, all_ac_domains, ac_domain->name, strlen(ac_domain->name), ac_domain);
+               rpmlog(RPMLOG_INFO, "package %s defined ac domain %s\n", ac_domain->pkg_name, ac_domain->name);         
+           }
+       }
+       int ret = msmSetSmackProvide(smack_accesses, provide, package->sw_source);
+
+       if (ret < 0) {
+               rpmlog(RPMLOG_ERR, "Failed to set smack rules for provide\n");
+               return -1;
+       }
+    }
+    return 0;
+}
+
+int msmSetupDBusPolicies(package_x *package) 
+{
+
+       dbus_x *session = NULL;
+       dbus_x *system = NULL;
+       provide_x *provide;
+       dbus_x *dbus;
+
+       for (provide = package->provides; provide; provide = provide->prev) {
+               for (dbus = provide->dbuss; dbus; dbus = dbus->prev) {
+                       if (!strcmp(dbus->bus, "session")) {
+                           msmSetupDBusConfig(package, dbus, session ? 1 : 0);
+                           session = dbus;
+                       } else if (!strcmp(dbus->bus, "system")) {
+                           msmSetupDBusConfig(package, dbus, system ? 1 : 0);
+                           system = dbus;
+                       } else return -1;
+               }
+               if (session) msmSetupDBusConfig(package, session, -1);
+               if (system) msmSetupDBusConfig(package, system, -1);
+       session = system = NULL;
+       }
+       return 0;
+
+}
+
+static int msmCheckDomainRequestOrPermit(manifest_x *mfx, const char* domain) 
+{
+
+       ac_domain_x *defined_ac_domain = NULL; 
+       char* name = NULL;
+
+       if ((!mfx) || (!domain))
+               return -1;
+
+       name = calloc(strlen(domain) + 1, sizeof(char));
+       if (!name) return -1;
+       strncpy(name, domain, strlen(domain));
+       strtok(name, ":");  // remove label name if present
+       rpmlog(RPMLOG_DEBUG, "label name %s domain name %s \n", domain, name);
+       
+       HASH_FIND(hh, all_ac_domains, name, strlen(name), defined_ac_domain);
+       if (!defined_ac_domain) { // request or permit for an undefined domain. 
+               rpmlog(RPMLOG_ERR, "A domain name %s hasn't been yet defined by any package. Can't verify if it is allowed\n", name);
+               msmFreePointer((void**)&name);
+               return -1;
+       }
+
+       //now check that this ac_domain can be requested
+
+        if ((mfx->define) && (mfx->define->name)) {
+               rpmlog(RPMLOG_DEBUG, "mfx->define->name %s domain %s\n", mfx->define->name, name);
+               if (strcmp(mfx->define->name, name) == 0) {
+                       // AC domain access is requested or permitted from the same package where it was defined. 
+                       // This case is always allowed
+                       msmFreePointer((void**)&name);
+                       return 0;               
+               }
+        } 
+
+        // no need to check if developer allowed other packages to request/permit this domain
+        // because this isn't a request to belong to a domain, but request/permit for domain access
+       
+       if (msmIsRequestAllowed(mfx, defined_ac_domain)) {
+           // request or permit is allowed by domain policy
+           rpmlog(RPMLOG_DEBUG, "Request/Permit to access a domain name %s is allowed based on package sw source\n", name);
+           msmFreePointer((void**)&name);
+           return 0;
+               
+       } else {
+           rpmlog(RPMLOG_ERR, "Request/Permit to access a domain name %s isn't allowed based on package sw source\n", name);
+           msmFreePointer((void**)&name);
+           return -1;
+       }
+}
+
+int msmSetupDefine(struct smack_accesses *smack_accesses, manifest_x *mfx)
+{
+    d_request_x *d_request;
+    d_permit_x *d_permit;
+    ac_domain_x * defined_ac_domain = NULL;
+    int ret;
+
+    if ( (!mfx) || (!mfx->define) || (!mfx->define->name)) {
+       rpmlog(RPMLOG_ERR, "Failed to setup define with empty name\n");
+       return -1;
+    }
+
+    /* need to check if domain hasn't been already defined by other package */
+
+    HASH_FIND(hh, all_ac_domains, mfx->define->name, strlen(mfx->define->name), defined_ac_domain);
+    if ((defined_ac_domain) && (defined_ac_domain->pkg_name)) { // this domain has been previously defined
+               if (strcmp(defined_ac_domain->pkg_name, mfx->name) != 0) {
+                       rpmlog(RPMLOG_ERR, "Attempt to define a domain name %s that has been already defined by package %s\n",
+                                                                                        mfx->define->name, defined_ac_domain->pkg_name);
+                       return -1;
+               }
+
+    }
+
+    if (mfx->define->d_requests) {
+           for (d_request = mfx->define->d_requests; d_request; d_request = d_request->prev) {
+                       // first check if the current's package sw source can grant access to requested domain
+                       if ( msmCheckDomainRequestOrPermit(mfx, d_request->label_name) < 0 )
+                               return -1;
+                       if ( smack_accesses_add(smack_accesses, mfx->define->name, d_request->label_name, d_request->ac_type) < 0 ) {
+                               rpmlog(RPMLOG_ERR, "Failed to set smack rules for domain requests\n");
+                               return -1;
+                       }       
+       
+           }
+    }
+
+    if (mfx->define->d_permits) {
+           for (d_permit = mfx->define->d_permits; d_permit; d_permit = d_permit->prev) {
+                       // first check if the current's package sw source can grant access to permited domain
+                       if ( msmCheckDomainRequestOrPermit(mfx, d_permit->label_name) < 0 )
+                               return -1;
+                       if (!d_permit->to_label_name)
+                               ret = smack_accesses_add(smack_accesses, d_permit->label_name, mfx->define->name, d_permit->ac_type);
+                       else {
+                               if ( msmCheckLabelProvisioning(mfx, d_permit->to_label_name) < 0 )
+                                       return -1;
+                               ret = smack_accesses_add(smack_accesses, d_permit->label_name, d_permit->to_label_name, d_permit->ac_type);
+                       }
+                       if (ret < 0) {
+                               rpmlog(RPMLOG_ERR, "Failed to set smack rules for domain permits\n");
+                               return -1;
+                       }       
+           }
+    }
+    return 0;
+}
+
+package_x *msmCreatePackage(const char *name, sw_source_x *sw_source, provide_x *provides, const char *modified)
+{
+    if (!name) return NULL;
+
+    package_x *package = calloc(1, sizeof(package_x));
+    if (package) {
+       package->name = strdup(name);
+       if (!package->name) goto exit;
+       package->sw_source = sw_source;
+       package->provides = provides;
+       if (modified) {
+           package->modified = strdup(modified);
+           if (!package->modified) goto exit;
+       }
+    }
+    return package;
+
+ exit:
+    msmFreePointer((void**)&package->name);
+    msmFreePointer((void**)&package->modified);
+    msmFreePointer((void**)&package);
+
+    return NULL;
+}
+
+int msmSetupSmackRules(struct smack_accesses *smack_accesses, const char* package_name, int flag, int SmackEnabled)
+{
+    int ret = 0;
+    char * buffer = calloc(strlen(SMACK_RULES_PATH) + strlen(package_name) + 1, sizeof(char));
+    if (!buffer) return -1;    
+    strncpy(buffer, SMACK_RULES_PATH, strlen(SMACK_RULES_PATH));
+    strncpy(buffer + strlen(SMACK_RULES_PATH), package_name, strlen(package_name));
+    rpmlog(RPMLOG_DEBUG, "smack rule file path %s, SmackEnabled %d\n", buffer, SmackEnabled);
+
+    if (flag == SMACK_UNINSTALL) { /* uninstallation case */
+       FILE* fd = fopen(buffer, "r");
+    if (fd) {
+        rpmlog(RPMLOG_DEBUG, "uninstall case \n");
+           struct smack_accesses *old_rule_set = NULL;
+           ret = smack_accesses_new(&old_rule_set);
+           if (ret != 0) return -1;
+           ret = smack_accesses_add_from_file(old_rule_set, fileno(fd));
+           if (ret == 0) {
+            if (SmackEnabled == 1) 
+               ret = smack_accesses_clear(old_rule_set); /* deletes rules from kernel */
+            
+        }
+        smack_accesses_free(old_rule_set);
+        fclose(fd);
+           remove(buffer); /* delete rules file from system */
+    }
+    } else { /*installation case */
+        /* first attempt to clean previous version of rules, if exists */
+           FILE* fd = fopen(buffer, "r");
+       if (fd) {
+                   struct smack_accesses *old_rule_set = NULL;
+                   ret = smack_accesses_new(&old_rule_set);
+                   if (ret != 0) return -1;
+                   ret = smack_accesses_add_from_file(old_rule_set, fileno(fd));
+               if (ret == 0) {
+                if (SmackEnabled == 1) 
+                    ret = smack_accesses_clear(old_rule_set); /* deletes old rules from kernel */
+            }
+                   fclose(fd);
+                   smack_accesses_free(old_rule_set);
+           } 
+        /* now write new rules to the system */
+        fd = fopen(buffer, "w");
+       if (!fd) {
+            rpmlog(RPMLOG_ERR, "Can't write smack rules\n");
+            return -1;
+        }
+       ret = smack_accesses_save(smack_accesses, fileno(fd));
+       rpmlog(RPMLOG_DEBUG, "ret in installation %d\n", ret);
+        if (!ret) {
+            if (SmackEnabled == 1) 
+                    ret = smack_accesses_apply(smack_accesses);
+        }
+       fclose(fd);
+    }
+    
+    free(buffer);
+    if (ret)
+        return -1;
+    return 0;  
+
+}
+
+int msmSetupPackages(struct smack_accesses *smack_accesses, package_x *packages, sw_source_x *sw_source)
+{
+    package_x *package, *first = NULL;
+    char *p_rankkey, *c_rankkey; 
+    for (package = packages; package; package = package->prev) {
+       package_x *current_p;
+            rpmlog(RPMLOG_DEBUG, "before HASH_FIND, package->name %s\n", package->name);
+       HASH_FIND(hh, allpackages, package->name, strlen(package->name), current_p);
+            rpmlog(RPMLOG_DEBUG, "after HASH_FIND\n");
+       if (current_p) {
+           if (!current_p->sw_source) {
+               return -1;
+           }
+           p_rankkey = strdup(package->sw_source->rankkey);
+           c_rankkey = strdup(current_p->sw_source->rankkey);
+           p_rankkey = strtok(p_rankkey, ".");
+           c_rankkey = strtok(c_rankkey, ".");
+           /* this is an upgrade, remove old one from config */
+           if ((strcmp(p_rankkey, c_rankkey) < 0) ||
+               (strcmp(package->sw_source->name, current_p->sw_source->name) == 0)) {
+               HASH_DELETE(hh, allpackages, current_p);
+               rpmlog(RPMLOG_INFO, "sw source %s upgraded package %s previously provided in sw source %s\n", 
+                                                               package->sw_source->name, package->name, current_p->sw_source->name);
+               current_p->newer = package;
+               package->older = current_p;
+           } else {
+               /* upgrade from lower or similary ranked sw source is not allowed */ 
+               rpmlog(RPMLOG_ERR, "sw source %s tried to upgrade package %s previously provided in sw source %s\n", 
+                                                               package->sw_source->name, package->name, current_p->sw_source->name);
+               return -1;
+           }
+           msmFreePointer((void**)&p_rankkey);
+           msmFreePointer((void**)&c_rankkey);
+       } else {
+           if (sw_source) {
+           rpmlog(RPMLOG_INFO, "sw source %s provided package %s\n", package->sw_source->name, package->name);
+           }
+       }
+       rpmlog(RPMLOG_DEBUG, "before HASH_ADD_KEYPTR\n");
+       HASH_ADD_KEYPTR(hh, allpackages, package->name, strlen(package->name), package);   
+       /* set sw source smack rules*/
+       if ((msmSetupProvides(smack_accesses, package)) < 0 ) {
+               msmCancelPackage(package->name);  
+               return -1;
+       }
+       first = package;
+    }
+    if (sw_source && packages) {
+       /* catenate list to sw_source config */
+       LISTCAT(sw_source->packages, first, packages);
+    }
+    return 0;
+}
+
+package_x *msmCheckPackage(const char *name)
+{
+    package_x *package = NULL;
+
+    if (name)
+       HASH_FIND(hh, allpackages, name, strlen(name), package);
+
+    return package;
+}
+
+static void msmCancelACDomain(const char *name)
+{
+    if (name) {
+       ac_domain_x *domain;
+       HASH_FIND(hh, all_ac_domains, name, strlen(name), domain);
+       if (domain) {
+           HASH_DELETE(hh, all_ac_domains, domain);
+           if (domain->older) {
+               /* resume previous version */
+               HASH_ADD_KEYPTR(hh, all_ac_domains, domain->older->name, strlen(domain->older->name), domain->older);
+               domain->older->older = domain->older->newer;
+               domain->older->newer = NULL;
+               domain->newer = domain->older;
+               domain->older = NULL;
+           } else {
+               /* no previous, just take this one out */
+               domain->newer = domain;
+           }
+       }
+    }
+}
+
+void msmCancelPackage(const char *name)
+{
+    provide_x *provide;
+    ac_domain_x *ac_domain;
+
+    if (name) {
+       package_x *package;
+       HASH_FIND(hh, allpackages, name, strlen(name), package);
+       if (package) {
+           HASH_DELETE(hh, allpackages, package);
+           if (package->older) {
+               /* resume previous version */
+               HASH_ADD_KEYPTR(hh, allpackages, package->older->name, strlen(package->older->name), package->older);
+               package->older->older = package->older->newer;
+               package->older->newer = NULL;
+               package->newer = package->older;
+               package->older = NULL;
+           } else {
+               /* no previous, just take this one out */
+               package->newer = package;
+           }
+          /* need to clean up the all_ac_domain list, too */
+          for (provide = package->provides; provide; provide = provide->prev) {
+               for (ac_domain = provide->ac_domains; ac_domain; ac_domain = ac_domain->prev) 
+                       msmCancelACDomain(ac_domain->name);
+          }
+       }
+    }
+}
+
+static int is_executable(const char* path, magic_t cookie) 
+{
+   const char* buffer = NULL;
+   int result = -1;
+   char* ptr = NULL;
+
+   if ((!path) || (!cookie))
+       return result;
+
+   buffer = magic_file(cookie, path);
+
+   rpmlog(RPMLOG_DEBUG, "buffer: %s\n", buffer);       
+
+   if (buffer != NULL) { 
+       ptr = strstr(buffer,"executable");
+       if (ptr) result = 0;    
+       ptr = strstr(buffer,"ELF");
+       if (ptr) result = 0;            
+   }
+
+   return result;
+}
+
+int msmSetFileXAttributes(manifest_x *mfx, const char* filepath, magic_t cookie) 
+{
+    provide_x *provide = NULL;
+    filesystem_x *filesystem = NULL;    
+    size_t len = 0, match = 0;
+    const char *label = NULL;
+    const char *exec_label = NULL;
+    const char *type = NULL;
+    const char isolatedLabel[] = SMACK_ISOLATED_LABEL;
+    struct stat st;
+
+    if (!filepath) return -1;
+    if (mfx->name) {
+       package_x *package = msmCheckPackage(mfx->name);
+       if (!package)
+               return -1;
+       for (provide = package->provides; provide; provide = provide->prev) {
+               for (filesystem = provide->filesystems; filesystem; filesystem = filesystem->prev) {
+                       if (!strcmp(filepath, filesystem->path)) {
+                           /* exact match */
+                           label = filesystem->label;
+                           exec_label = filesystem->exec_label;
+                           if (filesystem->type) type = filesystem->type;
+                           goto found;
+                       }
+
+                       len = strlen(filesystem->path);
+                       rpmlog(RPMLOG_DEBUG, "filesystem->path: %s, length %d\n", filesystem->path, len);
+                       rpmlog(RPMLOG_DEBUG, "filesystem->path + len - 1: %s\n", filesystem->path + len - 1);
+                       if (len > match) {
+                           if ((!strncmp(filepath, filesystem->path, len)) && (filesystem->type)) {
+                               /* partial match and the directory marked as transmutable*/
+                               label = filesystem->label;
+                               exec_label = filesystem->exec_label;
+                               match = len;
+                           }
+                           if (!strncmp(filesystem->path + len - 1, "*", 1)) { 
+                               if (!strncmp(filepath, filesystem->path, len - 1))  {
+                                   /* partial match and the path is marked with wildcard*/
+                                   label = filesystem->label;
+                                   exec_label = filesystem->exec_label;
+                                   match = len - 1;
+                               }
+                           }
+                       }
+               }
+       }
+    } else 
+       return -1;
+
+    found:
+       if ((!label) || (!exec_label)) {
+           /* no match, use default label of AC domain */
+           if (mfx->request) { //AC domain is requested in manifest
+               if (mfx->request->ac_domain) {
+                       if (!label) label = mfx->request->ac_domain;
+                       if (!exec_label) exec_label = mfx->request->ac_domain;
+               } else {
+                       rpmlog(RPMLOG_INFO, "Request for AC domain is empty. Can't identify default file label\n");
+                       rpmlog(RPMLOG_INFO, "File will be labelled with the label \"Isolated\"\n");
+                       if (!label) label = isolatedLabel;
+                       if (!exec_label) exec_label = isolatedLabel;
+               }
+            } else if (mfx->define) { // AC domain defined in manifest
+               if (mfx->define->name) {
+                       if (!label) label = mfx->define->name;
+                       if (!exec_label) exec_label = mfx->define->name;
+               } else {
+                       rpmlog(RPMLOG_INFO, "Define for AC domain is empty. Can't identify default file label\n");
+                       rpmlog(RPMLOG_INFO, "File will be labelled with the label \"Isolated\"\n");
+                       if (!label) label = isolatedLabel;
+                       if (!exec_label) exec_label = isolatedLabel;
+               }                
+            } else { // no request or definition of domain
+                       rpmlog(RPMLOG_INFO, "Both define and request sections are empty. Can't identify default file label\n");
+                       rpmlog(RPMLOG_INFO, "File will be labelled with the label \"Isolated\"\n");
+                       if (!label) label = isolatedLabel;
+                       if (!exec_label) exec_label = isolatedLabel;
+            }
+       } 
+
+       rpmlog(RPMLOG_INFO, "setting SMACK64 %s for %s\n", label, filepath);
+
+       if (lsetxattr(filepath, SMACK64, label, strlen(label), 0) < 0 ) {
+           rpmlog(RPMLOG_ERR, "Failed to set SMACK64 %s for %s: %s\n", 
+                  label, filepath, strerror(errno));
+       }
+
+       if ((is_executable(filepath, cookie)) == 0) {
+               if ((exec_label) && (strcmp(exec_label, "none") == 0)) {
+                       // do not set SMACK64EXEC
+                       rpmlog(RPMLOG_INFO, "not setting SMACK64EXEC for %s as requested in manifest\n", filepath);
+               } else {
+                       rpmlog(RPMLOG_INFO, "setting SMACK64EXEC %s for %s\n", exec_label, filepath);
+                       if (lsetxattr(filepath, SMACK64EXEC, exec_label, strlen(exec_label), 0) < 0 ) {
+                               rpmlog(RPMLOG_ERR, "Failed to set SMACK64EXEC %s for %s: %s\n", 
+                                       exec_label, filepath, strerror(errno));
+                       }
+               }
+       }
+               
+       if (type) { //marked as transmutable
+               if ((lstat(filepath, &st) != -1) && (S_ISDIR(st.st_mode))) { //check that it is a directory
+                       char at_true[] = "TRUE";
+                       rpmlog(RPMLOG_INFO, "setting SMACK64TRANSMUTE %s for %s\n", at_true, filepath);
+                       if ( lsetxattr(filepath, SMACK64TRANSMUTE, at_true, strlen(at_true), 0) < 0 ) {
+                           rpmlog(RPMLOG_ERR, "Failed to set SMACK64TRANSMUTE %s for %s: %s\n", 
+                                  at_true, filepath, strerror(errno));
+                       }
+               } else {
+                       rpmlog(RPMLOG_DEBUG, "No setting up of transmute attr for a non-directory, path %s\n", 
+                                  filepath);
+               }
+       
+       }
+
+    
+
+    return 0;
+
+}
+
+void msmRemoveRules(struct smack_accesses *smack_accesses, manifest_x *mfx, int SmackEnabled)
+{
+    provide_x *provide;
+    package_x *package;
+
+    HASH_FIND(hh, allpackages, mfx->name, strlen(mfx->name), package);
+    if (!package)
+       return;
+
+    if ((mfx->define) || (mfx->sw_sources)) {
+           /* remove smack rule file and rule set from kernel */
+       rpmlog(RPMLOG_DEBUG, "removing smack rules for %s\n", mfx->name);
+           msmSetupSmackRules(smack_accesses, mfx->name, SMACK_UNINSTALL, SmackEnabled);
+    }
+
+    for (provide = mfx->provides; provide; provide = provide->prev) {
+       if (provide->dbuss && !package->older) 
+           msmRemoveDBusConfig(package, provide->dbuss);
+
+    }
+
+}
+
+void msmRemoveConfig(manifest_x *mfx)
+{
+    package_x *package;
+
+    HASH_FIND(hh, allpackages, mfx->name, strlen(mfx->name), package);
+    if (package) {
+       if (!package->older) {
+           /* set newer to remove from config list */
+           package->newer = package;
+           rpmlog(RPMLOG_INFO, "removing package for %s\n", mfx->name);
+       }
+    }
+}
+
+sw_source_x *msmSWSourceTreeTraversal(sw_source_x *sw_sources, int (func)(sw_source_x *, void *, void*), void *param, void* param2)
+{
+    sw_source_x *sw_source;
+
+    if (sw_sources) {
+       LISTHEAD(sw_sources, sw_source);
+       /* sw source tree is actually a list ordered into tree traversal path */
+       for (; sw_source; sw_source = sw_source->next)
+           if (!sw_source->newer)
+               if (!(func)(sw_source, param, param2)) return sw_source;
+    }
+    return NULL;
+}
+
index 87b469b1320f01f875a948a61aefd09179030346..5962b5a35f1be359c4abe31c0b18432fa9828884 100644 (file)
@@ -24,8 +24,14 @@ rpmRC PLUGINHOOK_TSM_POST_FUNC(rpmts ts, int res);
 /* per transaction element plugin hooks */
 rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te);
 rpmRC PLUGINHOOK_PSM_POST_FUNC(rpmte te, int res);
+rpmRC PLUGINHOOK_VERIFY_FUNC(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig, DIGEST_CTX ctx, int res);
 
 /*per scriptlet plugin hooks */
 rpmRC PLUGINHOOK_SCRIPTLET_PRE_FUNC(const char *s_name, int type);
 rpmRC PLUGINHOOK_SCRIPTLET_FORK_POST_FUNC(const char *path, int type);
 rpmRC PLUGINHOOK_SCRIPTLET_POST_FUNC(const char *s_name, int type, int res);
+
+/*per file plugin hooks */
+rpmRC PLUGINHOOK_FSM_INIT_FUNC(const char* path, mode_t mode);
+rpmRC PLUGINHOOK_FSM_COMMIT_FUNC(const char* path, mode_t mode, int type);
+rpmRC PLUGINHOOK_FILE_CONFLICT_FUNC(rpmts ts, char* path, Header oldHeader, rpmfi oldFi, int rpmrc);