Security plugin: plugin hooks code refactoring and improvment 04/10304/1
authorElena Reshetova <elena.reshetova@intel.com>
Thu, 26 Sep 2013 08:30:54 +0000 (11:30 +0300)
committerElena Reshetova <elena.reshetova@intel.com>
Fri, 27 Sep 2013 07:41:47 +0000 (10:41 +0300)
Change-Id: I4d44db47865dd5c83fcf28435ffc26a70164b69d

plugins/msm-plugin.c
plugins/msm.h
plugins/msmconfig.c
plugins/msmmanifest.c
plugins/msmxattr.c

index 569f9a2..2290ac2 100644 (file)
@@ -35,7 +35,6 @@
 #include <sys/stat.h>
 
 #include <rpm/rpmfileutil.h>
-#include <rpm/rpmmacro.h>
 #include <rpm/rpmpgp.h>
 #include <rpm/rpmkeyring.h>
 #include <rpm/rpmdb.h>
@@ -77,165 +76,179 @@ typedef struct packagecontext {
     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 rpmts ts = NULL;                                /* rpm transaction */
+static manifest_x *dsp = 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 char* ownSmackLabel = NULL;             /* rpm smack security context */
+static int SmackEnabled = 0;                   /* indicates if Smack is enabled in kernel or not */
 static magic_t cookie = NULL;
 static int package_created = 0;
 
-static int copyFile(char *old_filename, char  *new_filename)
+/* Support functions */
+
+/**
+ * Frees the given pointer and sets it to NULL
+ * @param ptr  address of pointer to be freed
+ * @return NULL
+ */
+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;
+}
+
+/**
+ * Frees the given pointer and sets it to NULL
+ * @param ptr  address of pointer to be freed
+ * @return
+ */
+void msmFreePointer(void** ptr)
 {
-    FD_t ptr_old, ptr_new;
-    int res;
+    if (*ptr)
+        free(*ptr);
+    *ptr = NULL;
+    return;
+}
+
+/**
+ * Creates a new package context
+ * @param te   rpm te struct
+ * @return created package context
+ */
+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;
 
-    ptr_old = Fopen(old_filename, "r.fdio");
-    ptr_new = Fopen(new_filename, "w.fdio");
+    if (!headerIsEntry(h, RPMTAG_SECMANIFEST)) {
+        goto exit1;
+    }
 
-    if ((ptr_old == NULL) || (Ferror(ptr_old))) {
-        return  -1;
+    if (!headerGet(h, RPMTAG_SECMANIFEST, &msm, HEADERGET_MINMEM)) {
+        goto exit1;
     }
 
-    if ((ptr_new == NULL) || (Ferror(ptr_new))) {
-        Fclose(ptr_old);
-        return  -1;
+    count = rpmtdCount(&msm);
+    if (count != 1) {
+        goto exit2;
+    }
+
+    ctx->data = xstrdup(rpmtdNextString(&msm));
+    rpmlog(RPMLOG_DEBUG, "%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;
+        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);
 
-    res = ufdCopy(ptr_old, ptr_new);
+    return ctx;
+}
 
-    Fclose(ptr_new);
-    Fclose(ptr_old);
-    return res;
+/**
+ * Creates and adds a te package context to a context list
+ * @param te   rpm te struct
+ * @return created and added package context
+ */
+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;
 }
 
+/* -------------------- */
+
+/* Implementation of hooks */
+/* Hooks are listed in the call sequence inside rpm code */
+
 rpmRC PLUGINHOOK_INIT_FUNC(rpmts _ts, const char *name, const char *opts)
 {
     ts = _ts;
-    char *fullPath = NULL, *fullPath1 = NULL;
-    char *defaultPolicyPath = NULL;
-    struct stat buf;
 
     if (!ts)
         return RPMRC_FAIL;
 
-    fullPath = rpmGenPath(ts->rootDir, DEVICE_SECURITY_POLICY, NULL);
-    rpmlog(RPMLOG_DEBUG, "fullPath %s\n", fullPath);
-    if (!fullPath) {
-        rpmlog(RPMLOG_ERR, "Building a full path failed for device security policy\n");
-        goto plugin_error;
-    }
+    if (msmLoadDeviceSecurityPolicy(ts->rootDir, &dsp) == RPMRC_FAIL)
+        return RPMRC_FAIL;
 
-    if (stat(fullPath, &buf) != 0) { // the policy file is missing
-        if (ts->rootDir) { // we are running with --root option and policy is missing, need to copy it for now
-            // first create prefix for it
-            char *sysconfdir = rpmExpand("%{?_sysconfdir}", NULL);
-            if (!sysconfdir || !strcmp(sysconfdir, "")) {
-               rpmlog(RPMLOG_ERR, "Failed to expand %%_sysconfdir macro\n");
-                goto plugin_error;
-            }
-            fullPath1 = rpmGenPath(ts->rootDir, sysconfdir, NULL);
-            rpmlog(RPMLOG_DEBUG, "fullPath1 %s\n", fullPath1);
-            msmFreePointer((void**)&sysconfdir);
-            if (!fullPath1) {
-               rpmlog(RPMLOG_ERR, "Building a full path for sysconfdir failed\n");
-                goto plugin_error;
-            }
-            if (rpmioMkpath(fullPath1, 0755, getuid(), getgid()) != 0) {
-                    rpmlog(RPMLOG_ERR, "Failed to create a path for policy file\n");
-                    goto plugin_error;
-            }
-            defaultPolicyPath = rpmExpand("%{?__transaction_msm_default_policy}", NULL);
-            if (!defaultPolicyPath || !strcmp(defaultPolicyPath, "")) {
-                rpmlog(RPMLOG_ERR, "Failed to expand transaction_msm_default_policy macro\n");
-                goto plugin_error;
-            }
-            if(copyFile(defaultPolicyPath, fullPath) == -1) {
-               /* Do not allow plug-in to proceed without security policy existing */
-               rpmlog(RPMLOG_ERR, "Failed to copy the policy outside of chroot. Abort installation.\n");
-                goto plugin_error;
-            }
-       } else {
-            /* Do not allow plug-in to proceed without security policy existing */
-            rpmlog(RPMLOG_ERR, "Policy file is missing at %s. Abort installation.\n",
-                  fullPath);
-            goto plugin_error;
-        }
-    }
+    if (!dsp)
+        return RPMRC_FAIL;
 
-    rpmlog(RPMLOG_DEBUG, "reading device security policy from %s\n", fullPath);
-    root = msmProcessDevSecPolicyXml(fullPath);
+    /* smackfs path doesn't need to be prefixed with ts->rootDir 
+       since it is only used for loading rules to kernel and libsmack will load it
+       by itself to the correct path */
 
-    if (!root) {
-        rpmlog(RPMLOG_ERR, "Failed process sw sources from %s\n", fullPath);
-        goto plugin_error;
+    if (smack_smackfs_path() == NULL) {
+        rpmlog(RPMLOG_INFO, "Smackfs isn't mounted at %s. Going to the image build mode. \n", smack_smackfs_path());
+        ownSmackLabel = strdup("_");
+        SmackEnabled = 0;
     } else {
-        if (msmSetupSWSources(NULL, root, NULL)) {
-            rpmlog(RPMLOG_ERR, "Failed to setup security policy from %s\n",fullPath);
-            goto plugin_error;
-        }
-    }
-
-    msmFreePointer((void**)&fullPath);
-    msmFreePointer((void**)&fullPath1);
-    msmFreePointer((void**)&defaultPolicyPath);
-
-    fullPath = rpmGenPath(ts->rootDir, SMACK_LOAD_PATH, NULL);
-    rpmlog(RPMLOG_DEBUG, "fullPath for SMACK_LOAD_PATH %s\n", fullPath);
-    if (!fullPath) {
-        rpmlog(RPMLOG_ERR, "Building a full path for smack load failed\n");
-        goto plugin_error;
-    }
-
-    /* check its own security context and store it for the case when packages without manifest will be installed */
-    if (stat(fullPath, &buf) == 0) {
+        /* check its own security context and store it for the case when packages without manifest will be installed */
         int res = smack_new_label_from_self(&ownSmackLabel);
         SmackEnabled = 1;
         if (res < 0) {
             rpmlog(RPMLOG_ERR, "Failed to obtain rpm security context\n");
-            goto plugin_error;
-        }
-    } else {
-        rpmlog(RPMLOG_INFO, "Smackfs isn't mounted at %s. Going to the image build mode. \n", fullPath);
-        ownSmackLabel = strdup("_");
-        SmackEnabled = 0;
-    }
-
-    msmFreePointer((void**)&fullPath);    
-    fullPath = rpmGenPath(ts->rootDir, SMACK_RULES_PATH, NULL);
-    fullPath1 = rpmGenPath(ts->rootDir, SMACK_RULES_PATH_BEG, NULL);
-    rpmlog(RPMLOG_DEBUG, "fullPath for SMACK_RULES_PATH %s\n", fullPath);
-    rpmlog(RPMLOG_DEBUG, "fullPath1 for SMACK_RULES_PATH_BEG %s\n", fullPath1);
-    if ((!fullPath) || (!fullPath1)){
-        rpmlog(RPMLOG_ERR, "Building a full path failed for smack rules path\n");
-       goto plugin_error;
-    }
-
-    if (stat(fullPath, &buf) != 0) {
-        rpmlog(RPMLOG_DEBUG, "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(fullPath1, &buf) != 0) {
-            if (mkdir(fullPath1, mode) != 0) {
-                rpmlog(RPMLOG_ERR, "Failed to create a sub-directory for smack rules\n");
-                goto plugin_error;
-            }    
+            return RPMRC_FAIL;
         }
-        if (mkdir(fullPath, mode) != 0){
-            rpmlog(RPMLOG_ERR, "Failed to create a directory for smack rules\n");
-            goto plugin_error;
-        } 
     }
 
-    msmFreePointer((void**)&fullPath);    
-    msmFreePointer((void**)&fullPath1);    
-
     rpmlog(RPMLOG_DEBUG, "rpm security context: %s\n", ownSmackLabel);
 
+    if (msmSetupSmackRulesDir(ts->rootDir) == RPMRC_FAIL)
+        return RPMRC_FAIL;
+
     cookie = magic_open(0); 
     if (!cookie)
         return RPMRC_FAIL; 
@@ -248,18 +261,6 @@ rpmRC PLUGINHOOK_INIT_FUNC(rpmts _ts, const char *name, const char *opts)
     }
 
     return RPMRC_OK;
-
-plugin_error:
-    msmFreePointer((void**)&fullPath);
-    msmFreePointer((void**)&fullPath1);
-    msmFreePointer((void**)&defaultPolicyPath);
-    return RPMRC_FAIL;
-}
-
-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,
@@ -267,18 +268,23 @@ rpmRC PLUGINHOOK_FILE_CONFLICT_FUNC(rpmts ts, char* path,
                                      int rpmrc)
 {
     fileconflict *fc;
-    if (!path)
+    if ((!path) || (!dsp))
         return rpmrc;
 
-    rpmlog(RPMLOG_DEBUG, "FILE_CONFLICT_FUNC hook  path %s\n",path);
+    rpmlog(RPMLOG_DEBUG, "FILE_CONFLICT_FUNC hook path %s\n",path);
+
+    /* uncomment this code if you wish that plugin obeys --replacefiles rpm flag
+    if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES) {
+        return rpmrc;
+    } */
 
-    const char *name = headerGetString(oldHeader, RPMTAG_SECSWSOURCE);
+    const char *sw_source_name = headerGetString(oldHeader, RPMTAG_SECSWSOURCE);
     const char *pkg_name = headerGetString(oldHeader, RPMTAG_NAME);
-    if (!name || !root || !pkg_name) {
-        return rpmrc; /* no sw source(s) or package name - abnormal state */
+    if (!sw_source_name || !pkg_name) {
+        return rpmrc; /* no sw source or package name - abnormal state */
     }
 
-    sw_source_x *sw_source = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)name, NULL);
+    sw_source_x *sw_source = msmSWSourceTreeTraversal(dsp->sw_sources, msmFindSWSourceByName, (void *)sw_source_name, NULL);
     if (!sw_source)
         return rpmrc; /* no old sw_source - abnormal state */
 
@@ -301,77 +307,25 @@ rpmRC PLUGINHOOK_FILE_CONFLICT_FUNC(rpmts ts, char* path,
         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)
 {
-    if (!root) {
-        rpmlog(RPMLOG_DEBUG, "Policy is missing. Ending transaction\n");
+    if (!dsp) {
+        rpmlog(RPMLOG_ERR, "Device security policy is missing. Unable to proceed\n");
         return RPMRC_FAIL;
     }
 
     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;
-
-    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_ERR, "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) {
+    if (!dsp) {
         rpmlog(RPMLOG_ERR, "No device policy found\n");
-        rootSWSource = 1; /* accept any signed package as root */
         return rpmrc;
     } 
 
@@ -383,15 +337,15 @@ rpmRC PLUGINHOOK_VERIFY_FUNC(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig,
     if (rpmrc) {
         /* RPM failed to verify signature */
         rpmlog(RPMLOG_ERR, "Invalid signature, cannot search sw source\n");
-        return rpmrc;
+        goto exit;
     }
     if (sigtd->tag != RPMSIGTAG_RSA) {
         /* Not RSA, revert to unknown sw source. */
-        rpmlog(RPMLOG_DEBUG, "no RSA signature, cannot search sw source\n");
+        rpmlog(RPMLOG_DEBUG, "not an RSA signature, cannot search sw source\n");
         goto exit;
     }
 
-    current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceBySignature, sig, ctx);
+    current = msmSWSourceTreeTraversal(dsp->sw_sources, msmFindSWSourceBySignature, sig, ctx);
     if (current)
         rpmlog(RPMLOG_DEBUG, "signature matches sw source %s\n", current->name);
     else
@@ -399,11 +353,11 @@ rpmRC PLUGINHOOK_VERIFY_FUNC(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig,
 
  exit:
     if (!current) {
-        current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)"_default_", NULL);
+        current = msmSWSourceTreeTraversal(dsp->sw_sources, msmFindSWSourceByName, (void *)"_default_", NULL);
         if (current) {
             rpmlog(RPMLOG_DEBUG, "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);
+            current = msmSWSourceTreeTraversal(dsp->sw_sources, msmFindSWSourceByName, (void *)"root", NULL);
             if (current)
                 rpmlog(RPMLOG_DEBUG, "using _root_ sw source now for testing\n");
         }
@@ -412,85 +366,6 @@ rpmRC PLUGINHOOK_VERIFY_FUNC(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig,
     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_DEBUG, "%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;
@@ -502,18 +377,18 @@ rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te)
 
     package_created = 0;
 
-    if (!root && !rootSWSource) {
-        /* no sw source config, just exit */
-        goto exit;
+    if (!dsp) {
+        rpmlog(RPMLOG_ERR, "Device security policy is missing. Unable to proceed\n");
+        return RPMRC_FAIL;
     }
 
     if (!current) {
         /* this means that verify hook has not been called */
-        current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)"_default_", NULL);
+        current = msmSWSourceTreeTraversal(dsp->sw_sources, msmFindSWSourceByName, (void *)"_default_", NULL);
         if (current) {
             rpmlog(RPMLOG_DEBUG, "using _default_ sw source\n");
         } else { 
-            rpmlog(RPMLOG_ERR, "Default source isn't availiable. Package source can't be determined. Abort installation\n");
+            rpmlog(RPMLOG_ERR, "Default source isn't avaliable. Package source can't be determined. Abort installation\n");
             goto fail;
         }
     }
@@ -531,7 +406,7 @@ rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te)
         if (h) {
             const char *name = headerGetString(h, RPMTAG_SECSWSOURCE);
             if (name) { 
-                current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)name, NULL);
+                current = msmSWSourceTreeTraversal(dsp->sw_sources, msmFindSWSourceByName, (void *)name, NULL);
                 rpmlog(RPMLOG_DEBUG, "removing %s from sw source %s\n",
                       rpmteN(ctx->te), name);
             }
@@ -590,11 +465,12 @@ rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te)
         rpmlog(RPMLOG_DEBUG, "Installing the package\n");
         package_x *package = NULL;
 
-        if (rootSWSource) {
-            /* this is the first package */
+        /*if (rootSWSource) {
+            // this is the first package that brings the policy
             package = msmCreatePackage(mfx->name, mfx->sw_sources, 
                                            mfx->provides, NULL);
-        } else if (mfx->sw_source) {
+        } else */
+        if (mfx->sw_source) {
             /* all packages must have sw_source */
             package = msmCreatePackage(mfx->name, mfx->sw_source, 
                                            mfx->provides, NULL);
@@ -628,15 +504,17 @@ rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te)
         }
 
         package_created = 1;
-        if (rootSWSource) {
-            /* current is root */
-            root = ctx->mfx;
-        } 
+        
+        /*if (rootSWSource) {
+            // current configuration becomes dsp
+            dsp = ctx->mfx;
+        } */
 
         rpmlog(RPMLOG_DEBUG, "Starting the security setup...\n");
         unsigned int smackLabel = 0;
 
-        if (rootSWSource || ctx->mfx->sw_source) {
+        /*if (rootSWSource || ctx->mfx->sw_source) {*/
+        if (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);
@@ -719,7 +597,7 @@ rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te)
 
 rpmRC PLUGINHOOK_FSM_INIT_FUNC(const char* path, mode_t mode)
 {
-    //check if there any conflicts that prevent file being written to the disk
+    /* Check if there any conflicts that prevent file being written to the disk */
 
     fileconflict *fc;
     packagecontext *ctx = context;
@@ -735,8 +613,6 @@ rpmRC PLUGINHOOK_FSM_INIT_FUNC(const char* path, mode_t mode)
     if (cleanedPath)
         *cleanedPath = '\0';
 
-    //rpmlog(RPMLOG_DEBUG, "dupapth: %s\n", dupPath);
-
     HASH_FIND(hh, allfileconflicts, dupPath, strlen(dupPath), fc);
     msmFreePointer((void**)&dupPath);
 
@@ -761,13 +637,16 @@ rpmRC PLUGINHOOK_FSM_INIT_FUNC(const char* path, mode_t mode)
 
 rpmRC PLUGINHOOK_FSM_COMMIT_FUNC(const char* path, mode_t mode, int type)
 {
+    /* Setup xattrs for the given path */
+
     packagecontext *ctx = context;
+
+    rpmlog(RPMLOG_DEBUG, "Started with FSM_COMMIT_FUNC hook for file: %s\n", path);
+
     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);
+    /* the type option is ignored for now */
 
     if (ctx->mfx) {
         file_x *file = xcalloc(1, sizeof(*file));
@@ -818,10 +697,10 @@ rpmRC PLUGINHOOK_PSM_POST_FUNC(rpmte te, int rpmrc)
         return RPMRC_FAIL;
     }
 
-    if (rootSWSource) {
-        /* current is root */
-        root = context->mfx;
-    } 
+    /* if (rootSWSource) {
+        // current configuration becomes dsp
+        dsp = context->mfx;
+    } */
 
     if (rpmteType(ctx->te) == TR_REMOVED) {
         if (ctx->mfx->sw_source) {
@@ -847,27 +726,16 @@ rpmRC PLUGINHOOK_TSM_POST_FUNC(rpmts ts, int rpmrc)
     packagecontext *ctx = context;
     msmFreeInternalHashes(); // free hash structures first
 
-    if (root) {
-        msmSaveDeviceSecPolicyXml(root, ts->rootDir);
-        if (!rootSWSource) root = msmFreeManifestXml(root);
+    if (dsp) {
+        msmSaveDeviceSecPolicyXml(dsp, ts->rootDir);
+        /* if (!rootSWSource) dsp = msmFreeManifestXml(dsp); */
+        dsp = msmFreeManifestXml(dsp);
+
     }
     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)
 {
 
@@ -891,11 +759,3 @@ rpmRC PLUGINHOOK_CLEANUP_FUNC(void)
 
     return RPMRC_OK;
 }
-
-void msmFreePointer(void** ptr)
-{
-    if (*ptr)
-        free(*ptr);
-    *ptr = NULL;
-    return;
-}
index 1a4853a..f1bdcc8 100644 (file)
 #ifndef MSM_H
 #define MSM_H
 
-#define IMA "security.ima"
-#define SMACK64TRANSMUTE "security.SMACK64TRANSMUTE"
 #define SMACK64 "security.SMACK64"
 #define SMACK64EXEC "security.SMACK64EXEC"
+#define SMACK64TRANSMUTE "security.SMACK64TRANSMUTE"
 
 #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 "/sys/fs/smackfs/load"
 
 #define SMACK_ISOLATED_LABEL "Isolated"
 
@@ -312,6 +309,14 @@ void msmFreePointer(void **ptr);
 manifest_x *msmProcessManifestXml(const char *buffer, int size, sw_source_x *current, const char *packagename);
 
 /** \ingroup msm
+ * Loads device security policy.
+ * @param rootDir      --root rpm optional prefix
+ * @param dsp          pointer to the loaded policy
+ * @return             RPMRC_OK or RPMRC_FAIL
+ */
+rpmRC msmLoadDeviceSecurityPolicy(const char* rootDir, manifest_x **dsp);
+
+/** \ingroup msm
  * Process device security policy file.
  * @param filename     file name
  * @return             pointer to structure on success
@@ -319,6 +324,13 @@ manifest_x *msmProcessManifestXml(const char *buffer, int size, sw_source_x *cur
 manifest_x *msmProcessDevSecPolicyXml(const char *filename);
 
 /** \ingroup msm
+ * Creates a directory for the smack rules. 
+ * @param rootDir      --root rpm optional prefix
+ * @return             RPMRC_OK or RPMRC_FAIL
+ */
+rpmRC msmSetupSmackRulesDir(const char* rootDir);
+
+/** \ingroup msm
  * Free all structures reserved during manifest processing.
  * @param mfx          pointer to structure
  */
@@ -457,4 +469,30 @@ sw_source_x *msmSWSourceTreeTraversal(sw_source_x *sw_sources, int (func)(sw_sou
  * Free internal hashes.
  */
 void msmFreeInternalHashes(void);
+
+/** \ingroup msm
+ * Finds a sw source by key info.
+ * @param sw_source    sw source
+ * @param param                searched param
+ * @return             0 if found
+ */
+int msmFindSWSourceByKey(sw_source_x *sw_source, void *param);
+
+/** \ingroup msm
+ * Finds a sw source by sw source name.
+ * @param sw_source    sw source
+ * @param param                searched param
+ * @return             0 if found
+ */
+int msmFindSWSourceByName(sw_source_x *sw_source, void *param);
+
+/** \ingroup msm
+ * Finds a sw source by sw source signature.
+ * @param sw_source    sw source
+ * @param param                searched param
+ * @param param2       searched param2
+ * @return             0 if found
+ */
+int msmFindSWSourceBySignature(sw_source_x *sw_source, void *param, void* param2);
+
 #endif
index 81462fe..1551c6e 100644 (file)
@@ -30,6 +30,8 @@
 
 #include "rpmio/rpmbase64.h"
 #include "rpmio/rpmlog.h"
+#include "rpm/rpmfileutil.h"
+#include <rpm/rpmmacro.h>
 
 #include "msm.h"
 
@@ -273,3 +275,140 @@ rpmRC msmSaveDeviceSecPolicyXml(manifest_x *mfx, const char *rootDir)
     return rc;
 }
 
+/**
+ * Copies a file
+ * @param old_filename old file name
+ * @param new_filename new file name
+ * @return             result of copy or -1 on failure
+ */
+static int copyFile(char *old_filename, char  *new_filename)
+{
+    FD_t ptr_old, ptr_new;
+    int res;
+
+    ptr_old = Fopen(old_filename, "r.fdio");
+    ptr_new = Fopen(new_filename, "w.fdio");
+
+    if ((ptr_old == NULL) || (Ferror(ptr_old))) {
+        return  -1;
+    }
+
+    if ((ptr_new == NULL) || (Ferror(ptr_new))) {
+        Fclose(ptr_old);
+        return  -1;
+    }
+
+    res = ufdCopy(ptr_old, ptr_new);
+
+    Fclose(ptr_new);
+    Fclose(ptr_old);
+    return res;
+}
+
+/**
+ * Loads device security policy.
+ * @param rootDir      --root rpm optional prefix
+ * @param dsp          pointer to the loaded policy
+ * @return             RPMRC_OK or RPMRC_FAIL
+ */
+rpmRC msmLoadDeviceSecurityPolicy(const char* rootDir, manifest_x **dsp)
+{
+    char *dspFullPath = NULL, *dspFullPathDir = NULL;
+    char *defaultdspPath = NULL;
+    struct stat buf;
+
+    dspFullPath = rpmGenPath(rootDir, (const char*)DEVICE_SECURITY_POLICY, NULL);
+    rpmlog(RPMLOG_DEBUG, "Device Security policy full path %s\n", dspFullPath);
+    if (!dspFullPath) {
+        rpmlog(RPMLOG_ERR, "Building a full path failed for the device security policy\n");
+        goto ldsp_error;
+    }
+
+    if (stat(dspFullPath, &buf) != 0) { // the policy file is missing
+        if (rootDir) { // we are running with --root option and policy is missing, need to copy it for now
+            // first create prefix for it
+            char *sysconfdir = rpmExpand((const char*)"%{?_sysconfdir}", NULL);
+            if (!sysconfdir || !strcmp(sysconfdir, "")) {
+               rpmlog(RPMLOG_ERR, "Failed to expand %%_sysconfdir macro\n");
+                goto ldsp_error;
+            }
+
+            dspFullPathDir = rpmGenPath(rootDir, sysconfdir, NULL);
+            rpmlog(RPMLOG_DEBUG, "Device Security policy full path dir %s\n", dspFullPathDir);
+            msmFreePointer((void**)&sysconfdir);
+            if (!dspFullPathDir) {
+               rpmlog(RPMLOG_ERR, "Building a full path for the device security policy dir failed\n");
+                goto ldsp_error;
+            }
+            if (rpmioMkpath(dspFullPathDir, 0755, getuid(), getgid()) != 0) {
+                    rpmlog(RPMLOG_ERR, "Failed to create a path for the device security policy dir\n");
+                    goto ldsp_error;
+            }
+            defaultdspPath = rpmExpand((const char*)"%{?__transaction_msm_default_policy}", NULL);
+            if (!defaultdspPath || !strcmp(defaultdspPath, "")) {
+                rpmlog(RPMLOG_ERR, "Failed to expand transaction_msm_default_policy macro\n");
+                goto ldsp_error;
+            }
+            if(copyFile(defaultdspPath, dspFullPath) == -1) {
+               /* Do not allow plug-in to proceed without security policy existing */
+               rpmlog(RPMLOG_ERR, "Failed to copy the device security policy to the chroot environment\n");
+                goto ldsp_error;
+            }
+       } else {
+            /* Do not allow plug-in to proceed without security policy existing */
+            rpmlog(RPMLOG_ERR, "Policy file is missing at %s\n",
+                  dspFullPath);
+            goto ldsp_error;
+        }
+    }
+
+    rpmlog(RPMLOG_DEBUG, "reading the device security policy from %s\n", dspFullPath);
+    *dsp = msmProcessDevSecPolicyXml(dspFullPath);
+
+    if (!*dsp) {
+        rpmlog(RPMLOG_ERR, "Failed to process sw sources from %s\n", dspFullPath);
+        goto ldsp_error;
+    } else {
+        if (msmSetupSWSources(NULL, *dsp, NULL)) {
+            rpmlog(RPMLOG_ERR, "Failed to setup the device security policy from %s\n", dspFullPath);
+            goto ldsp_error;
+        }
+    }
+
+    return RPMRC_OK;
+
+ldsp_error:
+    msmFreePointer((void**)&dspFullPath);
+    msmFreePointer((void**)&dspFullPathDir);
+    msmFreePointer((void**)&defaultdspPath);
+    return RPMRC_FAIL;
+}
+
+/**
+ * Creates a directory for the smack rules. 
+ * @param rootDir      --root rpm optional prefix
+ * @return             RPMRC_OK or RPMRC_FAIL
+ */
+rpmRC msmSetupSmackRulesDir(const char* rootDir)
+{
+    char *smackRulesFullPath = NULL;
+    rpmRC res = RPMRC_FAIL;
+
+    smackRulesFullPath = rpmGenPath(rootDir, SMACK_RULES_PATH, NULL);
+    rpmlog(RPMLOG_DEBUG, "smackRulesFullPath for SMACK_RULES_PATH %s\n", smackRulesFullPath);
+
+    if (!smackRulesFullPath){
+        rpmlog(RPMLOG_ERR, "Building a full path failed for smack rules path\n");
+       return res;
+    }
+
+    if (rpmioMkpath(smackRulesFullPath, 0744, getuid(), getgid()) != 0) {
+        rpmlog(RPMLOG_ERR, "Failed to create a directory for smack rules\n");
+    } else {
+        res = RPMRC_OK;
+    }
+
+    msmFreePointer((void**)&smackRulesFullPath);
+    return res;
+}
+
index c713923..d1f211b 100644 (file)
@@ -822,7 +822,7 @@ static int msmProcessDefine(xmlTextReaderPtr reader, define_x *define, manifest_
     return ret;
 }
 
-static int findSWSourceByKey(sw_source_x *sw_source, void *param)
+int msmFindSWSourceByKey(sw_source_x *sw_source, void *param)
 {
     origin_x *origin;
     keyinfo_x *keyinfo;
@@ -839,6 +839,34 @@ static int findSWSourceByKey(sw_source_x *sw_source, void *param)
     return 1;
 }
 
+int msmFindSWSourceByName(sw_source_x *sw_source, void *param)
+{
+    const char *name = (const char *)param;
+    return strcmp(sw_source->name, name); 
+}
+
+int msmFindSWSourceBySignature(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;
+
+    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_ERR, "invalid sw source key\n");
+                return -1;
+            }
+            if (pgpVerifySignature(key, sig, ctx) == RPMRC_OK) {
+                return 0;
+            }
+        }
+    }
+    return 1;
+}
+
 static int msmProcessKeyinfo(xmlTextReaderPtr reader, origin_x *origin, sw_source_x *parent) 
 {
     const xmlChar *keydata;
@@ -858,7 +886,7 @@ static int msmProcessKeyinfo(xmlTextReaderPtr reader, origin_x *origin, sw_sourc
            }
            if (!ret) {
                // check that keys aren't matching
-               sw_source_x *old = msmSWSourceTreeTraversal(parent, findSWSourceByKey, (void *)keyinfo, NULL);
+               sw_source_x *old = msmSWSourceTreeTraversal(parent, msmFindSWSourceByKey, (void *)keyinfo, NULL);
                if (old) {
                    rpmlog(RPMLOG_ERR, "SW source with this key has already been installed\n");
                    return -1; 
@@ -976,12 +1004,6 @@ static int msmProcessAllow(xmlTextReaderPtr reader, sw_source_x *sw_source)
     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;
index eaf064d..0661ae3 100644 (file)
@@ -1194,8 +1194,8 @@ int msmSetFileXAttributes(manifest_x *mfx, const char* filepath, magic_t cookie)
                 }
                 len = strlen(filesystem->path);
                 rpmlog(RPMLOG_DEBUG, "filepath: %s, filesystem->type %s\n", filepath, filesystem->type);
-                rpmlog(RPMLOG_DEBUG, "filesystem->path: %s, length %d, match %d\n", filesystem->path, len, match);
-                rpmlog(RPMLOG_DEBUG, "filesystem->path + len - 1: %s\n", filesystem->path + len - 1);
+                //rpmlog(RPMLOG_DEBUG, "filesystem->path: %s, length %d, match %d\n", filesystem->path, len, match);
+                //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*/