4556102fe7fd2c2ce0f603a136e095c564b5e7a6
[platform/upstream/rpm.git] / plugins / msm-plugin.c
1 /*
2  * This file is part of MSM security plugin
3  * Greatly based on the code of MSSF security plugin
4  *
5  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
6  *
7  * Contact: Tero Aho <ext-tero.aho@nokia.com>
8  *
9  * Copyright (C) 2011 -2013 Intel Corporation.
10  *
11  * Contact: Elena Reshetova <elena.reshetova@intel.com>
12  *
13  * This program is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  * General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26  * 02110-1301 USA
27  */
28  
29 #include "plugin.h"
30 #include "debug.h"
31
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include <sys/wait.h>
36 #include <sys/prctl.h>
37 #include <sys/capability.h>
38 #include <sys/stat.h>
39
40 #include <rpm/rpmfileutil.h>
41 #include <rpm/rpmmacro.h>
42 #include <rpm/rpmpgp.h>
43 #include <rpm/rpmkeyring.h>
44 #include <rpm/rpmdb.h>
45
46 #include "rpmio/rpmbase64.h"
47 #include "rpmio/rpmlog.h"
48
49 #include "msm.h"
50
51 /*hooks that are used in msm plugin */
52
53 rpmPluginHook PLUGIN_HOOKS = \
54         PLUGINHOOK_INIT | \
55         PLUGINHOOK_CLEANUP | \
56         PLUGINHOOK_TSM_PRE | \
57         PLUGINHOOK_TSM_POST | \
58         PLUGINHOOK_PSM_PRE | \
59         PLUGINHOOK_PSM_POST | \
60         PLUGINHOOK_FSM_COMMIT | \
61         PLUGINHOOK_FSM_INIT | \
62         PLUGINHOOK_FILE_CONFLICT | \
63         PLUGINHOOK_VERIFY;
64
65
66 typedef struct fileconflict {
67     const char *path;
68     const char *pkg_name;
69     sw_source_x *sw_source;
70     UT_hash_handle hh;
71 } fileconflict;
72
73 typedef struct packagecontext {
74     char *data;                                 /*!< base64 manifest data */
75     manifest_x *mfx;                            /*!< parsed manifest data */
76     rpmte te;                                   /*!< related te */
77     struct packagecontext *next;                /*!< next in linked list */
78     struct smack_accesses *smack_accesses;      /*!<  handle to smack_accesses */
79 } packagecontext;
80
81 static rpmts ts = NULL;
82 static int rootSWSource= 0;
83 static manifest_x *root = NULL; /* pointer to device security policy file */
84 static packagecontext *context = NULL;
85 static sw_source_x *current = NULL;
86 static packagecontext *contextsHead = NULL;
87 static packagecontext *contextsTail = NULL;
88 static fileconflict *allfileconflicts = NULL;
89 static char* ownSmackLabel = NULL;
90 static int SmackEnabled = 0;
91 static magic_t cookie = NULL;
92 static int package_created = 0;
93
94 rpmRC PLUGINHOOK_INIT_FUNC(rpmts _ts, const char *name, const char *opts)
95 {
96     ts = _ts;
97     int res = 0;
98
99     rpmlog(RPMLOG_INFO, "reading device security policy from %s\n", DEVICE_SECURITY_POLICY);
100     root = msmProcessDevSecPolicyXml(DEVICE_SECURITY_POLICY);
101
102     if (root) {
103             if (msmSetupSWSources(NULL, root, NULL)) {
104                 rpmlog(RPMLOG_ERR, "Failed to setup device security policy from %s\n", 
105                        DEVICE_SECURITY_POLICY);
106                 return RPMRC_FAIL;
107             }
108     } else {
109             /* Do not allow plug-in to proceed without security policy existing */
110             rpmlog(RPMLOG_ERR, "Failed to process sw sources from %s\n", 
111                    DEVICE_SECURITY_POLICY);
112                 return RPMRC_FAIL;
113     }
114
115     /* check its own security context and store it for the case when packages without manifest will be installed */
116     struct stat buf;
117
118     if (stat(SMACK_LOAD_PATH, &buf) == 0) {
119         res = smack_new_label_from_self(&ownSmackLabel);
120         SmackEnabled = 1;
121         if (res != 0) {
122             rpmlog(RPMLOG_ERR, "Failed to obtain rpm security context\n");
123             return RPMRC_FAIL;
124         }
125     } else {
126         rpmlog(RPMLOG_INFO, "Smack disabled in kernel. Going to the image build mode. \n");
127         ownSmackLabel = strdup("_");
128         SmackEnabled = 0;
129     }
130
131     if (stat(SMACK_RULES_PATH, &buf) != 0) {
132         rpmlog(RPMLOG_INFO, "A directory for writing smack rules is missing. Creating one.\n");
133         mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH; // 644 -rwer--r--
134          if (stat(SMACK_RULES_PATH_BEG, &buf) != 0) {
135                 if (mkdir(SMACK_RULES_PATH_BEG, mode) != 0) {
136                         rpmlog(RPMLOG_ERR, "Failed to create a sub-directory for smack rules\n");
137                         return RPMRC_FAIL;
138                 }    
139          }
140         if (mkdir(SMACK_RULES_PATH, mode) != 0){
141             rpmlog(RPMLOG_ERR, "Failed to create a directory for smack rules\n");
142             return RPMRC_FAIL;
143         } 
144     }
145
146     rpmlog(RPMLOG_DEBUG, "rpm security context: %s\n", ownSmackLabel);
147
148     cookie = magic_open(0); 
149     if (!cookie)
150         return RPMRC_FAIL; 
151
152     if (magic_load(cookie, NULL) != 0) {
153         rpmlog(RPMLOG_ERR, "cannot load magic database - %s\n", magic_error(cookie));   
154        magic_close(cookie);
155        cookie = NULL;
156        return RPMRC_FAIL;
157     }
158     
159     return RPMRC_OK;
160 }
161
162 static int findSWSourceByName(sw_source_x *sw_source, void *param, void* param2)
163 {
164     const char *name = (const char *)param;
165     return strcmp(sw_source->name, name); 
166 }
167
168 rpmRC PLUGINHOOK_FILE_CONFLICT_FUNC(rpmts ts, char* path,
169                                       Header oldHeader, rpmfi oldFi, 
170                                       int rpmrc)
171 {
172     fileconflict *fc;
173     if (!path)
174         return rpmrc; 
175     rpmlog(RPMLOG_DEBUG, "FILE_CONFLICT_FUNC hook  path %s\n",path);
176
177     const char *name = headerGetString(oldHeader, RPMTAG_SECSWSOURCE);    
178     if (!name || !root) {
179             return rpmrc; /* no sw source(s) - abnormal state */
180     }
181     const char *pkg_name = headerGetString(oldHeader, RPMTAG_NAME);
182
183     sw_source_x *sw_source = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)name, NULL);
184     if (!sw_source)
185             return rpmrc; /* no old sw_source - abnormal state */
186
187     HASH_FIND(hh, allfileconflicts, path, strlen(path), fc);
188     if (!fc) {
189             /* Add new file conflict into hash */
190             fc = xcalloc(1, sizeof(*fc));
191             if (!fc) return RPMRC_FAIL;
192             fc->path = path;
193             fc->sw_source = sw_source;
194             fc->pkg_name = pkg_name;
195             HASH_ADD_KEYPTR(hh, allfileconflicts, path, strlen(path), fc);
196     } else {
197             /* Many packages have installed the same file */
198             if (strcmp(sw_source->rankkey, fc->sw_source->rankkey) <= 0) {
199                 /* Change sw source to the higher ranked one */
200                 fc->sw_source = sw_source;
201             }
202             msmFreePointer((void**)&path);
203     }
204     
205     if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES) {
206         /* Conflict has been noted, now return ok. It will be actually */
207         /* resolved later when conflicting package signature is verified */
208         /* and sw_source is known. */
209             return rpmrc;
210     }
211     return rpmrc;
212 }
213
214 rpmRC PLUGINHOOK_TSM_PRE_FUNC(rpmts ts)
215 {
216     return RPMRC_OK;
217 }
218
219 static int findSWSourceBySignature(sw_source_x *sw_source, void *param, void* param2)
220 {
221     origin_x *origin;
222     keyinfo_x *keyinfo;
223     pgpDigParams sig = (pgpDigParams)param;
224     DIGEST_CTX ctx = (DIGEST_CTX)param2;
225     pgpDigParams key = NULL;
226     int res = 0;
227     
228     for (origin = sw_source->origins; origin; origin = origin->prev) {
229             for (keyinfo = origin->keyinfos; keyinfo; keyinfo = keyinfo->prev) {
230                 if (pgpPrtParams(keyinfo->keydata, keyinfo->keylen, PGPTAG_PUBLIC_KEY, &key)) {
231                         rpmlog(RPMLOG_INFO, "invalid sw source key\n");
232                         return -1;
233                 }
234                 if (pgpVerifySignature(key, sig, ctx) == RPMRC_OK) {
235                         return 0;
236                 }
237             }
238     }
239     return 1;
240 }
241
242 rpmRC PLUGINHOOK_VERIFY_FUNC(rpmKeyring keyring, rpmtd sigtd, pgpDigParams sig, DIGEST_CTX ctx, int rpmrc)
243 {
244     current = NULL;
245
246 #if 0 
247     if (!root) {
248         if (rpmrc == RPMRC_NOKEY) {
249             rpmlog(RPMLOG_INFO, "package verified as root sw source\n");
250             rootSWSource = 1; /* accept any signed package as root */
251             return RPMRC_OK;
252         }
253         rpmlog(RPMLOG_ERR, "No device security policy, cannot verify signature\n");
254         return rpmrc;
255     } 
256
257
258 // make currently that even non-signed package with root policy will be treated as trusted
259
260    if (!root) {
261             rpmlog(RPMLOG_INFO, "package verified as root sw source\n");
262             rootSWSource = 1; /* accept any signed package as root */
263             return RPMRC_OK;
264    } 
265
266 //------------------
267 #endif
268
269    if (!root) {
270             rpmlog(RPMLOG_INFO, "No device policy found\n");
271             rootSWSource = 1; /* accept any signed package as root */
272             return rpmrc;
273    } 
274
275     if (rpmrc == RPMRC_NOKEY) {
276             /* No key, revert to unknown sw source. */
277             rpmlog(RPMLOG_INFO, "no key for signature, cannot search sw source\n");
278             goto exit;
279     }
280     if (rpmrc) {
281             /* RPM failed to verify signature */
282             rpmlog(RPMLOG_ERR, "Invalid signature, cannot search sw source\n");
283             return rpmrc;
284     }
285     if (sigtd->tag != RPMSIGTAG_RSA) {
286             /* Not RSA, revert to unknown sw source. */
287             rpmlog(RPMLOG_INFO, "no RSA signature, cannot search sw source\n");
288             goto exit;
289     }
290     current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceBySignature, sig, ctx);
291     if (current)
292             rpmlog(RPMLOG_INFO, "signature matches sw source %s\n", current->name);
293     else
294             rpmlog(RPMLOG_INFO, "valid signature but no matching sw source\n");
295
296  exit:
297     if (!current) {
298             current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)"_default_", NULL);
299             if (current)
300                 rpmlog(RPMLOG_INFO, "using _default_ sw source\n");
301         else { // for now in case default sw source isn't there yet, allow to think that it is coming from root
302                 current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)"root", NULL);
303                     if (current)
304                         rpmlog(RPMLOG_INFO, "using _root_ sw source now for testing\n");
305             }
306     }
307
308     return rpmrc;
309 }
310
311 static packagecontext *msmNew(rpmte te)
312 {
313     Header h;
314     struct rpmtd_s msm;
315     int count;
316     packagecontext *ctx = NULL;
317     const char *sw_source = NULL;
318
319     rpmtdReset(&msm);
320     
321     h = rpmteHeader(te);
322     if (!h) return NULL;
323     
324     ctx = xcalloc(1, sizeof(*ctx));
325     if (!ctx) {
326             goto exit1;
327     }
328     ctx->te = te;
329
330     if (!headerIsEntry(h, RPMTAG_SECMANIFEST)) {
331             goto exit1;
332     }
333
334     if (!headerGet(h, RPMTAG_SECMANIFEST, &msm, HEADERGET_MINMEM)) {
335             goto exit1;
336     }
337
338     count = rpmtdCount(&msm);
339     if (count != 1) {
340             goto exit2;
341     }
342
343     ctx->data = xstrdup(rpmtdNextString(&msm));
344     rpmlog(RPMLOG_INFO, "%s manifest b64 data: %.40s...\n", 
345            rpmteN(ctx->te), ctx->data);
346   
347  exit2:
348     rpmtdFreeData(&msm);
349  exit1:
350     if (rpmteType(ctx->te) == TR_ADDED) {
351             /* Save sw_source name into database, we need it when package */
352             /* is removed because signature verify is not called then. */
353             if (current) sw_source = current->name;
354             else if (rootSWSource) sw_source = rpmteN(ctx->te);
355             
356             if (!sw_source || !headerPutString(h, RPMTAG_SECSWSOURCE, sw_source)) {
357                 rpmlog(RPMLOG_ERR, "Failed to save sw source for %s, sw_source: %s\n", 
358                        rpmteN(ctx->te), sw_source);
359                 msmFreePointer((void**)&ctx->data);
360                 msmFreePointer((void**)&ctx);
361             }
362     }
363     headerFree(h);
364
365     return ctx;
366 }
367
368 static packagecontext *msmAddTE(rpmte te)
369 {
370     packagecontext *ctx = msmNew(te);
371     if (ctx) {
372         /* add the new policy to the list */
373             if (!contextsHead) {
374                 contextsHead = ctx;
375                 contextsTail = ctx;
376             } else {
377                 if (rpmteType(te) == TR_ADDED) {
378                         /* add to the end of the list */
379                         contextsTail->next = ctx;
380                         contextsTail = ctx;
381                 } else {
382                         /* add to the beginning of the list */
383                         ctx->next = contextsHead;
384                         contextsHead = ctx;
385                 }
386             }
387     }
388     return ctx;
389 }
390
391 rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te)
392 {
393     packagecontext *ctx = NULL;
394     manifest_x *mfx = NULL;
395     char *xml = NULL;
396     size_t xmllen;
397     rpmRC rc = RPMRC_OK;
398     int ret = 0;
399
400     if (!root && !rootSWSource) {
401         /* no sw source config, just exit */
402         goto exit;
403     }
404
405     if (!current) {
406         /* this means that verify hook has not been called */
407         current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)"_default_", NULL);
408             if (current)
409                 rpmlog(RPMLOG_INFO, "using _default_ sw source\n");
410         else { 
411             rpmlog(RPMLOG_ERR, "Default source isn't availiable. Package source can't be determined. Abort installation\n");
412                 goto fail;
413             }
414     }
415
416     ctx = msmAddTE(te);
417     if (!ctx) {
418             rpmlog(RPMLOG_ERR, "Failed to create security context for %s\n",
419                rpmteNEVRA(te));
420             goto fail;
421     }
422
423     if (rpmteType(ctx->te) == TR_REMOVED) {
424
425             /* Verify hook is not called before remove, */
426             /* so get the sw_source name from package header */
427             Header h = rpmteHeader(te);
428             if (h) {
429                 const char *name = headerGetString(h, RPMTAG_SECSWSOURCE);
430                 if (name) { 
431                     current = msmSWSourceTreeTraversal(root->sw_sources, findSWSourceByName, (void *)name, NULL);
432                     rpmlog(RPMLOG_INFO, "removing %s from sw source %s\n",
433                        rpmteN(ctx->te), name);
434                 }
435                 headerFree(h);
436             }
437             /* if (!current) {
438                 rpmlog(RPMLOG_INFO, "no sw source for removing %s\n", rpmteN(ctx->te));
439                 goto exit;
440             }*/
441     }
442
443     if (!ctx->data) {
444         rpmlog(RPMLOG_INFO, "No manifest in this package. Creating default one\n");
445
446         /* create default manifest manually. Make the package to belong to the domain where rpm is running */
447
448         mfx = calloc(1, sizeof(manifest_x));
449         if (!mfx)  goto fail;
450         mfx->sw_source = current;
451         mfx->name = strdup(rpmteN(ctx->te));
452         mfx->request = calloc(1, sizeof(request_x));
453         if (!mfx->request) {
454                 msmFreePointer((void**)&mfx->name);
455                 msmFreePointer((void**)&mfx);
456                 goto fail;
457         }
458         mfx->request->ac_domain = strdup(ownSmackLabel);
459         rpmlog(RPMLOG_DEBUG, "Done with manifest creation\n");
460         
461     } else {
462         if (rpmBase64Decode(ctx->data, (void **) &xml, &xmllen) != 0) {
463                 rpmlog(RPMLOG_ERR, "Failed to decode manifest for %s\n",
464                     rpmteN(ctx->te));
465                 goto fail;
466         }
467
468         rpmlog(RPMLOG_INFO, "parsing %s manifest: \n%s", rpmteN(ctx->te), xml);
469         mfx = msmProcessManifestXml(xml, xmllen, current, rpmteN(ctx->te));
470
471         if (!mfx) {
472                 rpmlog(RPMLOG_ERR, "Failed to parse manifest for %s\n",
473                 rpmteN(ctx->te));
474                 goto fail;
475         }
476     }
477
478
479     ctx->mfx = mfx;
480
481     int res = smack_accesses_new(&(ctx->smack_accesses)); 
482     if (res != 0) {
483             rpmlog(RPMLOG_ERR, "Failed to create smack access set\n");
484             goto fail;
485     }
486
487     if (rpmteType(ctx->te) == TR_ADDED) {
488
489         rpmlog(RPMLOG_DEBUG, "Installing the package\n");
490
491         package_x *package = NULL;
492
493         if (rootSWSource) {
494                 /* this is the first package */
495                 package = msmCreatePackage(mfx->name, mfx->sw_sources, 
496                                             mfx->provides, NULL);
497         } else if (mfx->sw_source) {
498                 /* all packages must have sw_source */
499                 package = msmCreatePackage(mfx->name, mfx->sw_source, 
500                                             mfx->provides, NULL);
501         } else {
502                 rpmlog(RPMLOG_ERR, "Package doesn't have a sw source. Abnormal situation. Abort.\n");
503                 goto fail;
504         }
505
506         if (!package) {
507                  rpmlog(RPMLOG_ERR, "Package could not be created. \n");
508                  goto fail; 
509         }
510             
511         mfx->provides = NULL; /* owned by package now */
512
513         if (!package->sw_source) { /* this must never happen */
514                 rpmlog(RPMLOG_ERR, "Install failed. Check that configuration has at least root sw source installed.\n");
515                 msmFreePackage(package);
516                 package = NULL;
517                 goto fail;
518         }
519             
520         rpmlog(RPMLOG_INFO, "adding %s manifest data to system, package_name %s\n", 
521                    rpmteN(ctx->te), package->name);
522
523         if (msmSetupPackages(ctx->smack_accesses, package, package->sw_source)) {
524                 rpmlog(RPMLOG_ERR, "Package setup failed for %s\n", rpmteN(ctx->te) );
525                 msmFreePackage(package);
526                 package = NULL;
527                 goto fail;
528         }
529
530         if (rootSWSource) {
531                 /* current is root */
532                 root = ctx->mfx;
533         } 
534
535         rpmlog(RPMLOG_DEBUG, "Starting the security setup...\n");
536         unsigned int smackLabel = 0;
537
538         if (rootSWSource || ctx->mfx->sw_source) {
539                 if (ctx->mfx->sw_sources) {
540                         smackLabel = 1; /* setting this one on since this manifest doesn't have any define/request section */
541                         ret = msmSetupSWSources(ctx->smack_accesses, ctx->mfx, ts);
542                         if (ret) {
543                             rpmlog(RPMLOG_ERR, "SW source setup failed for %s\n",
544                                    rpmteN(ctx->te));
545                             msmCancelPackage(ctx->mfx->name);
546                             goto fail;
547                         }
548                 }           
549                 if (ctx->mfx->define) {
550                         if (ctx->mfx->define->name)
551                                 smackLabel = 1;
552                                 ret = msmSetupDefine(ctx->smack_accesses, ctx->mfx);
553                                 if (ret) {
554                                         rpmlog(RPMLOG_ERR, "AC domain setup failed for %s\n",
555                                                 rpmteN(ctx->te));
556                                         msmCancelPackage(ctx->mfx->name);
557                                         goto fail;
558                                 }
559                         }           
560                 if (ctx->mfx->request) {        
561                         if (ctx->mfx->request->ac_domain)
562                                 smackLabel = 1;
563                                 ret = msmSetupRequests(ctx->mfx);
564                                 if (ret) {
565                                         rpmlog(RPMLOG_ERR, "Request setup failed for %s\n",
566                                                 rpmteN(ctx->te));
567                                         msmCancelPackage(ctx->mfx->name);
568                                         goto fail;
569                                 }
570                         }
571                 if (ctx->smack_accesses) {
572                         ret = msmSetupSmackRules(ctx->smack_accesses, ctx->mfx->name, 0, SmackEnabled);
573                         smack_accesses_free(ctx->smack_accesses);
574                         ctx->smack_accesses = NULL;
575                         if (ret) {
576                                 rpmlog(RPMLOG_ERR, "Setting up smack rules for %s failed\n",
577                                         rpmteN(ctx->te));
578                                 msmCancelPackage(ctx->mfx->name);
579                                 goto fail; 
580                         }
581                }
582                if (package->provides) {
583                         ret = msmSetupDBusPolicies(package);
584                         if (ret) {
585                             rpmlog(RPMLOG_ERR, "Setting up dbus policies for %s failed\n",
586                                    rpmteN(ctx->te));
587                             msmCancelPackage(ctx->mfx->name);
588                             goto fail;
589                         }
590                 }
591        
592                 /* last check is needed in order to catch in advance 
593                 the situation when no ac domain defined or requested */
594                 if (smackLabel == 0) {
595                         rpmlog(RPMLOG_ERR, "No ac domain defined or requested for package %s. Abort.\n",   rpmteN(ctx->te));
596                         msmCancelPackage(ctx->mfx->name);
597                         goto fail;
598                 }
599         }
600
601
602         } else if (rpmteDependsOn(ctx->te)) { /* TR_REMOVED */
603                 rpmlog(RPMLOG_INFO, "upgrading package %s by %s\n",
604                         rpmteNEVR(ctx->te), rpmteNEVR(rpmteDependsOn(ctx->te)));
605         } else if (mfx->sw_sources) {
606                 rpmlog(RPMLOG_ERR, "Cannot remove sw source package %s\n",
607                         rpmteN(ctx->te));
608                 goto fail;
609         }
610
611         rpmlog(RPMLOG_DEBUG, "Finished with pre psm hook \n");
612         package_created = 1;
613
614         goto exit;
615
616  fail: /* error, cancel the rpm operation */
617         rc = RPMRC_FAIL;
618
619  exit: /* success, continue rpm operation */
620         context = ctx;
621         msmFreePointer((void**)&xml);
622
623         return rc;
624 }
625
626 rpmRC PLUGINHOOK_FSM_INIT_FUNC(const char* path, mode_t mode)
627 {
628
629     //check if there any conflicts that prevent file being written to the disk
630
631     fileconflict *fc;
632     packagecontext *ctx = context;
633     char * cleanedPath = NULL, *dupPath = NULL;
634     
635     rpmlog(RPMLOG_DEBUG, "Started with FSM_INIT_FUNC hook for file: %s\n", path);
636     
637     if (!ctx) return RPMRC_FAIL; 
638     if (!path) return RPMRC_FAIL; 
639            
640     dupPath = strdup(path);
641     cleanedPath = strchr(dupPath, ';');
642     if (cleanedPath)
643         *cleanedPath = '\0';
644         
645     //rpmlog(RPMLOG_DEBUG, "dupapth: %s\n", dupPath);
646     
647     HASH_FIND(hh, allfileconflicts, dupPath, strlen(dupPath), fc);
648     msmFreePointer((void**)&dupPath);
649
650     if (fc) {
651         //rpmlog(RPMLOG_DEBUG, "rpmteN(ctx->te) %s fc->pkg_name: %s\n", rpmteN(ctx->te), fc->pkg_name);
652         /* There is a conflict, see if we are not allowed to overwrite */
653             if ((!current || (strcmp(current->rankkey, fc->sw_source->rankkey) >= 0)) && (strcmp(rpmteN(ctx->te), fc->pkg_name))){
654                 rpmlog(RPMLOG_ERR, "%s has file conflict in %s from sw source %s\n",
655                        rpmteN(ctx->te), fc->path, fc->sw_source->name);
656                 return RPMRC_FAIL;
657             }
658             rpmlog(RPMLOG_INFO, "%s from %s overwrites %s from %s\n",
659                    rpmteN(ctx->te), current->name, fc->path, fc->sw_source->name);
660     }
661
662     rpmlog(RPMLOG_DEBUG, "Finished with FSM_INIT_FUNC hook for file: %s\n", path);
663     
664     return RPMRC_OK;
665 }
666
667 rpmRC PLUGINHOOK_FSM_COMMIT_FUNC(const char* path, mode_t mode, int type)
668 {
669     packagecontext *ctx = context;
670     if (!ctx) return RPMRC_FAIL;
671     if (!path) return RPMRC_FAIL;
672
673     /* the type is ignored for now */
674     
675     rpmlog(RPMLOG_DEBUG, "Started with FSM_COMMIT_FUNC hook for file: %s\n", path);
676
677     if (ctx->mfx) {
678         file_x *file = xcalloc(1, sizeof(*file));
679         if (file) {
680                 file->path = strndup(path, strlen(path) + 1);
681                 LISTADD(ctx->mfx->files, file);
682                 if (rpmteType(ctx->te) == TR_ADDED) {
683                         if (msmSetFileXAttributes(ctx->mfx, file->path, cookie) < 0) {
684                                 rpmlog(RPMLOG_ERR, "Setting of extended attributes failed for file %s from package %s\n",
685                                                 file->path, rpmteN(ctx->te));
686                                 return RPMRC_FAIL;
687                         }
688                 } 
689
690         } else
691                 return RPMRC_FAIL;
692     } else {
693                 rpmlog(RPMLOG_ERR, "Manifest is missing while it should be present for the package %s\n",
694                            rpmteN(ctx->te));
695                 return RPMRC_FAIL;
696     }
697
698     rpmlog(RPMLOG_DEBUG, "Finished with FSM_COMMIT_FUNC hook for file: %s\n", path);
699     return RPMRC_OK;
700 }
701
702 rpmRC PLUGINHOOK_PSM_POST_FUNC(rpmte te, int rpmrc)
703 {
704
705     int ret = 0;
706     packagecontext *ctx = context;
707     if (!ctx) return RPMRC_FAIL;
708     
709     if (!package_created) {
710         /* failure in rpm pre psm hook, rollback */
711         return RPMRC_FAIL;
712     }
713     
714     if (rpmrc) {
715         /* failure in rpm psm, rollback */
716         if (rpmteType(ctx->te) == TR_ADDED)
717             msmCancelPackage(ctx->mfx->name);
718             goto exit;
719     }
720
721     if (!ctx->mfx){
722         rpmlog(RPMLOG_ERR, "Manifest is missing while it should be present for the package %s\n",
723                            rpmteN(ctx->te));
724                 goto exit;
725     }
726
727     if (rootSWSource) {
728             /* current is root */
729             root = context->mfx;
730     } 
731
732
733     if (rpmteType(ctx->te) == TR_REMOVED) {
734             if (ctx->mfx->sw_source) {
735                 if (rpmteDependsOn(ctx->te)) {
736                         rpmlog(RPMLOG_INFO, "upgrading %s manifest data\n", 
737                            rpmteN(ctx->te));
738                 } else {
739                         rpmlog(RPMLOG_INFO, "removing %s manifest data\n", 
740                            rpmteN(ctx->te));
741                     if (ctx->mfx->define || ctx->mfx->provides || ctx->mfx->sw_sources) {
742                             msmRemoveRules(ctx->smack_accesses, ctx->mfx, SmackEnabled);
743                     }       
744                     msmRemoveConfig(ctx->mfx);
745                 }
746             }
747
748    }
749
750  exit:
751     current = NULL;
752
753     if (ret) {
754             return RPMRC_FAIL;
755     }
756     return rpmrc;
757 }
758
759 rpmRC PLUGINHOOK_TSM_POST_FUNC(rpmts ts, int rpmrc)
760 {
761     packagecontext *ctx = context;
762     if (!ctx) return RPMRC_FAIL;
763     return RPMRC_OK;
764 }
765
766 static packagecontext *msmFree(packagecontext *ctx)
767 {
768
769     while (ctx) {
770             packagecontext *next = ctx->next;
771             msmFreePointer((void**)&ctx->data);
772             ctx->mfx = msmFreeManifestXml(ctx->mfx);
773             if (ctx->smack_accesses) smack_accesses_free(ctx->smack_accesses);
774             msmFreePointer((void**)&ctx);
775             ctx = next;
776     }
777
778     return NULL;
779
780 }
781
782 rpmRC PLUGINHOOK_CLEANUP_FUNC(void)
783 {
784
785     msmFreeInternalHashes(); // free hash structures first
786
787     if (root) {
788             msmSaveDeviceSecPolicyXml(root);
789             if (!rootSWSource)  root = msmFreeManifestXml(root);
790     }
791
792     ts = NULL;
793
794     contextsHead = contextsTail = msmFree(contextsHead);
795     contextsHead = contextsTail = NULL;
796
797     if (allfileconflicts) {
798             fileconflict *fc, *temp;
799             HASH_ITER(hh, allfileconflicts, fc, temp) {
800                 HASH_DELETE(hh, allfileconflicts, fc);
801                 msmFreePointer((void**)&fc->path);
802                 msmFreePointer((void**)&fc);
803             }
804     }
805
806     msmFreePointer((void**)&ownSmackLabel);
807     if (cookie) magic_close(cookie);
808
809     return RPMRC_OK;
810 }
811
812 const char *msmQueryPackageFile(const char *rfor, 
813                                  const char **dname, const char **pname)
814 {
815     int match = 0;
816     const char *path = NULL;
817
818     if (ts) {
819             char *sep = strchr(rfor, ':');
820             if (sep && sep[1] == ':' && sep[2] == '/') 
821                 path = &sep[2];
822             if (!path) return NULL;
823
824             rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, path, 0);
825             if (!mi)
826                 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, path, 0);
827             if (mi) {
828                 Header h;
829                 const char *name, *sw_source;
830                 while ((h = rpmdbNextIterator(mi))) {
831                         rpmdbCheckSignals();
832                         name = headerGetString(h, RPMTAG_NAME);
833                         sw_source = headerGetString(h, RPMTAG_SECSWSOURCE);
834                         if (name && sw_source) {
835                             match = !strncmp(rfor, name, path - rfor - 2);
836                             rpmlog(RPMLOG_INFO, "file %s belongs to package %s in sw source %s %s\n", path, name, sw_source, (match ? "(matched request)" : ""));
837                             if (match) {
838                                     *pname = xstrdup(name);
839                                     *dname = xstrdup(sw_source);
840                                     break;
841                             }
842                         }
843                 }
844                 mi = rpmdbFreeIterator(mi);
845             }
846     }
847     return match ? path : NULL;
848 }
849
850 void msmFreePointer(void** ptr)
851 {
852         if (*ptr)
853                 free(*ptr);
854         *ptr = NULL;
855         return;
856 }